
    <html lang="zh-cn">
    <head>
    <meta content="text/html; charset=utf-8" http-equiv="content-type" />
    <link href="F:\v_awjliu\BKDocs\ZH/default.css" rel="stylesheet">
    </head>
    <body>
    <h1 id="_1">接入指引</h1>
<h2 id="_2">基本接入</h2>
<ol>
<li>阅读 产品介绍及接入流程 (10 分钟)<ul>
<li><a href="../../权限中心/产品白皮书/产品简介/README.md">产品说明</a></li>
<li><a href="GuideFlow.md">接入流程</a></li>
</ul>
</li>
<li>阅读 快速开始(30 分钟)<ul>
<li><a href="../QuickStart/01-Begin.md">简介</a></li>
<li><a href="../QuickStart/02-Prepare.md">准备工作</a></li>
<li><a href="../QuickStart/03-Model.md">模型注册</a></li>
<li><a href="../QuickStart/04-Auth.md">鉴权</a></li>
<li><a href="../QuickStart/05-Application.md">无权限申请</a></li>
<li><a href="../QuickStart/06-More.md">了解更多</a></li>
</ul>
</li>
<li>梳理 系统的权限模型</li>
<li>
<p>阅读 接入样例(30 分钟)
    通过接入样例, 可以快速理解各种业务场景对应的权限模型</p>
<ul>
<li><a href="Examples/01-ActionWithoutResource.md">样例 1: 无关联实例权限</a></li>
<li><a href="Examples/02-ActionWithResource.md">样例 2: 关联简单实例权限</a></li>
<li><a href="Examples/03-Topology.md">样例 3: 使用拓扑层级管理权限</a></li>
<li><a href="Examples/04-Attribute.md">样例 4: 使用属性管理权限</a></li>
<li><a href="Examples/05-ActionGroup.md">样例 5: 配置操作组优化权限申请</a></li>
<li><a href="Examples/06-CommonActions.md">样例 6: 配置常用操作优化权限申请</a></li>
<li><a href="Examples/07-RelatedActions.md">样例 7: 配置依赖操作优化权限申请</a></li>
<li><a href="Examples/08-NoPermissionApply.md">样例 8: 系统间调用无权限申请</a></li>
<li><a href="Examples/10-OpenSource.md">开源项目: 接入权限中心的实现</a></li>
<li>阅读 权限中心接口协议相关说明 (10 分钟)</li>
<li><a href="../Reference/API/01-Overview/01-BackendAPIvsESBAPI.md">后台 API 和 ESB API 说明</a></li>
<li><a href="../Reference/API/01-Overview/02-APIBasicInfo.md">接口协议前置说明</a></li>
<li><a href="../Reference/API/01-Overview/03-APIAuth.md">系统间接口鉴权</a></li>
<li>注册权限模型到权限中心</li>
<li><a href="../Reference/NamingRules.md">系统注册名词规范</a></li>
<li><a href="../Explanation/01-instanceSelection.md">说明: 实例视图</a></li>
<li><a href="../Explanation/05-AppcodeAndSystemID.md">AppCode 和 SystemID 说明</a></li>
<li><a href="../Reference/API/02-Model/00-API.md">模型注册 API</a></li>
<li><a href="Solutions/Migration.md">权限模型自动初始化及更新 migration</a></li>
</ul>
<p>建议使用 json 通过 migration 进行模型注册, 方便后续维护及升级; 如果使用了 python sdk, 可以利用 sdk 的封装将模型注册 migration 整合到 django migration 中
7. 接入系统实现相关资源反向拉取接口
- <a href="../Reference/API/01-Overview/03-APIAuth.md">系统间接口鉴权</a>
- <a href="../Reference/API/03-Callback/01-API.md">资源拉取 API</a></p>
<p>如果使用了 python sdk, 可以通过封装的 dispatcher 实现相应 API
8. 接入系统实现鉴权逻辑
使用 SDK 进行鉴权(推荐, 常规 SaaS/中大型系统)
- <a href="../Reference/SDK/01-PythonSDK.md">Python SDK</a>
- <a href="../Reference/SDK/02-GoSDK.md">Go SDK</a>
- <a href="../Reference/API/04-Auth/01-SDK.md">SDK 鉴权</a></p>
<p>非 SDK 鉴权(直接鉴权, 小型系统/脚本/定时任务等无法使用 SDK 的情况)
- <a href="../Reference/API/04-Auth/02-DirectAPI.md">直接鉴权</a>
9. 实现无权限交互逻辑</p>
<ul>
<li><a href="Solutions/NoPermissionApply.md">无权限交互方案</a></li>
<li><a href="../Reference/API/05-Application/01-GenerateURL.md">生成无权限申请 URL</a></li>
<li><a href="../Reference/API/05-Application/02-NoPermissionData.md">第三方鉴权失败返回权限申请数据协议</a></li>
</ul>
</li>
</ol>
<h2 id="_3">增强功能</h2>
<ol>
<li>新建关联
    当新建一个资源时, 需要给某些人自动授予某些权限, 例如新建一个业务, 自动授予创建者 A 用户业务查看, 业务编辑, 业务删除的权限<ul>
<li><a href="Solutions/ResourceCreatorAction.md">新建关联权限方案</a></li>
<li><a href="../Reference/API/07-ResourceCreatorAction/01-Attribute.md">新建关联属性授权接口</a></li>
</ul>
</li>
<li>依赖操作
    用户在申请操作 A 权限时, 操作 A 依赖于操作 B, IAM 在创建申请单时会同时帮用户申请操作 B 的权限 例如申请<code>开发应用</code>的权限时, 会自动申请<code>访问开发者中心</code>权限, 这样存在依赖关系的权限就不需要额外单独申请<ul>
<li><a href="Solutions/RelatedActions.md">依赖操作权限方案</a></li>
<li><a href="Examples/07-RelatedActions.md">样例 7: 配置依赖操作优化权限申请</a></li>
<li><a href="../Reference/API/02-Model/13-Action.md">操作(Action)</a></li>
</ul>
</li>
<li>操作组
    如果系统注册的操作非常多, 在权限中心申请权限时默认是没有分类展示的, 可以额外进行分组<ul>
<li><a href="../Reference/API/02-Model/14-ActionGroup.md">操作组(ActionGroup)</a></li>
<li><a href="Examples/05-ActionGroup.md">样例 5: 配置操作组优化权限申请</a></li>
</ul>
</li>
<li>常用操作
    接入系统可以根据使用场景, 将操作进行<code>组合</code>, 作为常用操作方便用户申请<ul>
<li><a href="../Reference/API/02-Model/17-CommonActions.md">常用操作配置(CommonActions)</a></li>
<li><a href="Examples/06-CommonActions.md">样例 6: 配置常用操作优化权限申请</a></li>
</ul>
</li>
</ol>
<h1 id="_4">高级接入</h1>
<ol>
<li>授权及回收<ul>
<li><a href="../Explanation/06-LargeScaleInstances.md">大规模实例级权限限制</a></li>
<li><a href="../Reference/API/06-GrantRevoke/01-Topology.md">资源拓扑授权/回收</a></li>
<li><a href="../Reference/API/06-GrantRevoke/02-BatchTopology.md">批量资源拓扑授权/回收</a></li>
</ul>
</li>
<li>
<p>查询类 API</p>
<ul>
<li><a href="../Reference/API/08-Query/01-PolicyGet.md">policy get 获取某条策略详情</a></li>
<li><a href="../Reference/API/08-Query/02-PolicyList.md">policy list 拉取系统下某个操作的策略列表(翻页)</a></li>
<li><a href="../Reference/API/08-Query/03-PolicySubjects.md">policy subjects 根据策略 ID 拉群策略对应的用户信息</a></li>
</ul>
</li>
<li>
<p>LBAC</p>
</li>
</ol>
<p>注意, 这个方案是为了满足一些特殊场景而设计的, 本身的实现成本非常高, 如无相应的需求, 不需要关注</p>
<p>- 基于 LBAC+RBAC 的接入方案</p>
<h1 id="_5">其他链接</h1>
<ol>
<li>常见问题<ul>
<li><a href="FAQ/Guide.md">问题排查指引</a></li>
<li><a href="FAQ/ErrorCode.md">错误码</a></li>
<li><a href="FAQ/Debug/SaaS-Callback.md">常见: SaaS 回调接入系统失败</a></li>
<li><a href="FAQ/Debug/SaaS-DeptSync.md">常见: SaaS 组织架构同步异常</a></li>
<li><a href="FAQ/Debug/PolicyAPIDebug.md">常见: 为什么有权限/无权限</a>
- <a href="../../权限中心/产品白皮书/常见问题/Diffv2v3.md">产品相关</a></li>
</ul>
</li>
<li>API<ul>
<li><a href="../Reference/API/01-Overview/01-BackendAPIvsESBAPI.md">后台 API 和 ESB API 说明</a></li>
<li><a href="../Reference/API/01-Overview/02-APIBasicInfo.md">接口协议前置说明</a></li>
<li><a href="../Reference/API/01-Overview/03-APIAuth.md">系统间接口鉴权</a></li>
</ul>
</li>
<li>附加阅读<ul>
<li><a href="../Reference/Expression/01-Schema.md">表达式定义</a></li>
<li><a href="../Explanation/06-LargeScaleInstances.md">大规模实例级权限限制</a></li>
</ul>
</li>
<li>部署及运维<ul>
<li><a href="OPS/Deploy.md">部署及运维说明</a></li>
<li><a href="OPS/Upgrade.md">升级部署说明</a></li>
<li><a href="OPS/Develop.md">开发测试环境搭建</a></li>
<li><a href="../Reference/Benchmark.md">性能测试说明</a></li>
</ul>
</li>
</ol><h1 id="_1">接入流程图</h1>
<h2 id="_2">注册应用</h2>
<p><img alt="flow_01" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/flow_01.png" /></p>
<h2 id="_3">主体流程</h2>
<p><img alt="flow_02" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/flow_02.png" /></p>
<h2 id="_4">模型注册顺序</h2>
<p>注意: 
- 优化项可选, 用于提升用户权限申请/配置体验
- 基础模型中, 如果操作不关联任何资源, 那么不需要注册资源类型及实例视图</p>
<p><img alt="flow_03" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/flow_03.png" /></p><h1 id="_1">错误码</h1>
<h2 id="_2">错误码总览</h2>
<table>
<thead>
<tr>
<th align="left">错误码</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">1901002</td>
<td align="left">参数错误</td>
</tr>
<tr>
<td align="left">1901400</td>
<td align="left">用户传入的参数非法 (bad request)</td>
</tr>
<tr>
<td align="left">1901401</td>
<td align="left">没有权限调用接口 (unauthorized)</td>
</tr>
<tr>
<td align="left">1901403</td>
<td align="left">无访问权限</td>
</tr>
<tr>
<td align="left">1901404</td>
<td align="left">资源不存在 (not found)</td>
</tr>
<tr>
<td align="left">1901409</td>
<td align="left">资源冲突 (conflict)</td>
</tr>
<tr>
<td align="left">1901500</td>
<td align="left">500 系统错误 (system error)</td>
</tr>
<tr>
<td align="left">1902000</td>
<td align="left">依赖系统 api 不可达</td>
</tr>
<tr>
<td align="left">1902001</td>
<td align="left">ESB api 调用错误</td>
</tr>
<tr>
<td align="left">1902101</td>
<td align="left">IAM 后台请求返回码非 0</td>
</tr>
<tr>
<td align="left">1902102</td>
<td align="left">请求 ENGINE 错误</td>
</tr>
<tr>
<td align="left">1902301</td>
<td align="left">用户管理 api 调用错误</td>
</tr>
<tr>
<td align="left">1902400</td>
<td align="left">请求通用错误</td>
</tr>
<tr>
<td align="left">1902409</td>
<td align="left">请求数据与已存在数据有冲突</td>
</tr>
<tr>
<td align="left">1902412</td>
<td align="left">请求参数校验错误</td>
</tr>
<tr>
<td align="left">1902413</td>
<td align="left">请求第三方接口失败</td>
</tr>
<tr>
<td align="left">1902414</td>
<td align="left">请求参数 JSON 格式错误</td>
</tr>
<tr>
<td align="left">1902415</td>
<td align="left">请求方法不支持</td>
</tr>
<tr>
<td align="left">1902416</td>
<td align="left">请求参数错误</td>
</tr>
<tr>
<td align="left">1902417</td>
<td align="left">操作数据检查错误</td>
</tr>
<tr>
<td align="left">1902418</td>
<td align="left">用户组转出错误</td>
</tr>
<tr>
<td align="left">1902419</td>
<td align="left">请求数值错误</td>
</tr>
<tr>
<td align="left">1902401</td>
<td align="left">用户未登录</td>
</tr>
<tr>
<td align="left">1902403</td>
<td align="left">用户无权限访问</td>
</tr>
<tr>
<td align="left">1902404</td>
<td align="left">数据不存在</td>
</tr>
<tr>
<td align="left">1902200</td>
<td align="left">接入系统资源接口请求失败</td>
</tr>
<tr>
<td align="left">1902201</td>
<td align="left">接入系统资源接口请求 API 认证失败</td>
</tr>
<tr>
<td align="left">1902204</td>
<td align="left">接入系统不存在请求的资源类型或未实现该资源的查询方法</td>
</tr>
<tr>
<td align="left">1902206</td>
<td align="left">搜索 Keyword 参数校验失败</td>
</tr>
<tr>
<td align="left">1902222</td>
<td align="left">接入系统需返回的资源内容过多，拒绝返回数据</td>
</tr>
<tr>
<td align="left">1902229</td>
<td align="left">请求频率超出接入系统 API 频率限制</td>
</tr>
<tr>
<td align="left">1902250</td>
<td align="left">接入系统自身接口异常</td>
</tr>
<tr>
<td align="left">1902250</td>
<td align="left">接入系统自身接口返回数据不符合要求</td>
</tr>
<tr>
<td align="left">1902501</td>
<td align="left">ITSM 请求返回码非 0</td>
</tr>
<tr>
<td align="left">1902502</td>
<td align="left">ITSM 流程里存在 IAM 不支持的流程处理者</td>
</tr>
</tbody>
</table>
<h2 id="_3">后台错误码</h2>
<p>注意, 如果想确认目前环境中注册的权限模型, </p>
<p>可以用接口 <a href="../../Reference/API/02-Model/15-CommonQuery.md">权限模型: 通用查询 Common Query API</a> 查询.</p>
<h3 id="1901400">1901400</h3>
<blockquote>
<p>bad request: {message}</p>
</blockquote>
<p>用户传入的参数非法, 不符合规范. 详细信息在 message 中</p>
<p>需要仔细接口协议, 确保调用的 URL/参数等符合要求</p>
<p>举例: <code>bad request:json decode or validate fail, err=[0]: Key: 'commonActionSerializer.Actions' Error:Field validation for 'Actions' failed on the 'gt' tag</code> 常用操作<code>actions</code>必须至少一个 (使用了开源validation库的validate规则, 提示信息可能没那么清晰)</p>
<blockquote>
<p>bad request:action.id invalid</p>
</blockquote>
<p><code>action.id</code>非法, 确认下这个环境注册的权限模型中是否有这个操作</p>
<p>可以使用<a href="../../Reference/API/02-Model/15-CommonQuery.md">权限模型: 通用查询 Common Query API</a> 查询确认</p>
<blockquote>
<p>bad request:get system(xxxx) valid clients fail, err=[Cache:GetSystemClients] LocalSystemClientsCache.Get key=<code>xxx</code> fail =&gt; [SystemSVC:Get] saasManager.Get id=<code>xxx</code> fail =&gt; [Raw:Error] sql: no rows in result set</p>
</blockquote>
<p>找不到这个注册的系统</p>
<p>确认系统是否注册</p>
<h3 id="1901401">1901401</h3>
<blockquote>
<p>unauthorized: app code and app secret required</p>
</blockquote>
<p>请求 header 中没有传递 <code>X-Bk-App-Code/X-Bk-App-Secret</code></p>
<blockquote>
<p>unauthorized: app code or app secret wrong</p>
</blockquote>
<p>请求 header 中传递的 <code>X-Bk-App-Code/X-Bk-App-Secret</code> 错误, 无法在该环境找到匹配的.</p>
<p>需要确认:
- 是否传递了 <code>X-Bk-App-Code/X-Bk-App-Secret</code> 且非空
- 对应的 <code>app_code</code> 和 <code>app_secret</code> 是在同一个环境生成的
- 再次确认 <code>app_code/app_secret</code> 是否同应用详情页信息匹配(经常出现的是复制错/复制漏)`
- 由于认证存在缓存，第一次错误后，相同 AppCode 和 AppSecret 必须等待 5 秒以上才能再请求
- 如果无法确认, 请提供请求详情.</p>
<blockquote>
<p>unauthorized: app(xxx) is not allowed to call system (yyy) api" </p>
</blockquote>
<p>xxx 这个 app_code 不允许调用系统 yyy 的资源, 需要将 xxx 加入到 yyy 的 clients`中. 具体见  <a href="../../Reference/API/02-Model/10-System.md">系统(System) API</a></p>
<h3 id="1901404">1901404</h3>
<blockquote>
<p>not found: system(xxx) not exists </p>
</blockquote>
<p>系统 xxx 不存在, 请确认系统已注册(注意, system 是接入系统注册到权限中心的, <code>clients</code>中配置的是可以调用这个系统 API 的合法<code>app_code</code>, 不要混淆二者概念)</p>
<h3 id="1901409">1901409</h3>
<blockquote>
<p>conflict:instance selection name[xxxx] already exists</p>
</blockquote>
<p>资源冲突, 接口创建的<code>xxxx</code>已存在.</p>
<p>可以使用<a href="../../Reference/API/02-Model/15-CommonQuery.md">权限模型: 通用查询 Common Query API</a> 查询确认</p>
<blockquote>
<p>conflict:action has releated policies, you can't delete it or update the related_resource_types unless delete all the related policies. please contact administrator.</p>
</blockquote>
<p>操作已经被使用配置了相关的权限, 不能删除 action 或者改变这个 action 的 related_resource_types. 联系管理员, 通过权限中心 SaaS 的 Django Command 进行<code>权限升级</code>或者<code>权限清理</code>;</p>
<h3 id="1901500">1901500</h3>
<blockquote>
<p>[SubjectSVC:GetPK] GetPK _type=user, id=xxx fail =&gt; [Raw:Error] sql: no rows in result set</p>
</blockquote>
<p>原因: 用户在权限中心不存在, 新增用户未同步到权限中心, 或者用户被删除.</p>
<p>处理: 在用户管理新增用户后, 需要到权限中心做一次同步(同步所有组织架构需要 10 分钟左右)</p>
<p>默认权限中心从用户管理一天同步一次组织架构.</p>
<blockquote>
<p>request resources not match action =\u003e [Raw:Error] validateActionResource fail</p>
</blockquote>
<p>用户请求查询时传入的资源(resources) 同接入系统注册操作的关联资源类型(related_resource_types)不匹配</p>
<p>例如注册查看主机关联的资源类型是<code>主机</code>, 但是查询策略的时候传入的<code>action=查看主机, resources=[集群]</code> 此时校验操作的资源类型失败</p>
<p>确认是否是以下场景:</p>
<ul>
<li>操作关联了两个资源类型, 鉴权只传一个</li>
<li>操作关联资源类型 A, 鉴权时传递资源类型 B</li>
</ul>
<blockquote>
<p>[Cache:GetActionPK] ActionPKCache.Get key={system_x}:{action_y} fail =&gt; [Raw:Error] sql: no rows in result set</p>
</blockquote>
<p>用户请求传入的 action 在权限中心不存在(即 action 不在系统注册的操作列表中)</p>
<p>可能原因: 
1. 接入系统没有注册对应的<code>action</code>
2. 鉴权请求传入了错误的<code>action.id</code>
3. 接入系统变更了模型, 例如删除 action </p>
<h2 id="1902xxx-190230x">组件调用错误 1902XXX - 190230X</h2>
<p>日志查询方法:</p>
<p>找到权限中心 SaaS 的 component.log 日志, 搜索对应的请求 request_id, 查询相关 api 调用的上下文</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/ErrorCodes_1.png" /></p>
<h3 id="1902000">1902000</h3>
<p>描述: 依赖系统(esb, 权限中心后台, 用户管理) api 调用不可达</p>
<p>错误信息:</p>
<blockquote>
<p>request esb api error</p>
</blockquote>
<p>排查权限中心 SaaS 的主机是否能正常访问 ESB api</p>
<blockquote>
<p>request usermanger api error</p>
</blockquote>
<p>排查权限中心 SaaS 的主机是否能正常访问用户管理的 ESB api</p>
<blockquote>
<p>request iam api error</p>
</blockquote>
<p>排查权限中心 SaaS 的主机是否能正常访问权限中心后台 api</p>
<h3 id="1902001">1902001</h3>
<p>描述: 调用 ESB api 失败</p>
<p>提供错误信息与日志到 ESB 负责人排查</p>
<h3 id="1902200">1902200</h3>
<p>描述: 接入系统回调接口调用错误</p>
<p>错误信息:</p>
<blockquote>
<p>unreachable interface call</p>
</blockquote>
<p>接入系统接口不可达</p>
<blockquote>
<p>interface status code:<code>xxx</code>error</p>
</blockquote>
<p>接入系统接口返回状态码<code>xxx</code>错误</p>
<blockquote>
<p>Parameter error: The resource(system_id:bk_xxxx, type:page, id:244) display_name cannot be queried through the API - fetch_instance_info</p>
</blockquote>
<p>回调接口, 查询 244 资源实例时报错; 需要到被调用系统确认</p>
<p>无权限申请, 对于传入的数据，我们需要严格校验，这时候会回调 接入系统资源 fetch_instance_info接口查询资源名称</p>
<h3 id="1902201">1902201</h3>
<p><code>接入系统资源接口请求API认证失败</code>; </p>
<p>逻辑:
- 接入系统注册系统信息及回调接口, 权限中心会生成一个 token
- 权限中心回调接入系统, 会使用 basic auth, <code>username=bk_iam, password={token}</code>, 具体文档见 <a href="../../Reference/API/01-Overview/03-APIAuth.md">接口间调用鉴权</a>
- 接入系统接口, 会查询自己系统的 token,  <a href="../../Reference/API/02-Model/16-Token.md">系统 token 查询 API</a>, 进行比对
    - 如果使用的是 <code>iam-python-sdk</code>, 那么调用的是<code>IAM.get_token(system)</code>, 注意参数是<code>system</code>, 不是<code>app_code</code>
    - 如果使用了 <code>iam-python-sdk</code> 的 <code>DjangoBasicResourceApiDispatcher(iam, system)</code>, 注意参数是<code>system</code>, 不是<code>app_code</code>
- 比对失败, 返回 401, 权限中心报错误码 <code>1902201</code></p>
<p>某些场景下, 例如上云环境, app_code 和 system 是不一致的, 如果出现这个错误码, 大概率是使用<code>DjangoBasicResourceApiDispatcher</code>传递<code>system</code>参数错误</p>
<h3 id="1902250">1902250</h3>
<blockquote>
<p>接入系统自身接口异常</p>
</blockquote>
<p>调用接入系统接口失败</p>
<blockquote>
<p>接入系统自身接口返回数据进行JSON解析出错</p>
</blockquote>
<p>返回数据非json或json数据有问题</p>
<blockquote>
<p>接入系统自身接口返回数据不符合要求</p>
</blockquote>
<p>没有按协议要求返回<code>list</code>/<code>dict</code></p>
<p>出现以上问题, 需要找<strong>对应接入系统的开发人员</strong>排查解决</p>
<h3 id="1902301">1902301</h3>
<p>描述: 调用用户管理 api 失败</p>
<p>提供错误信息与日志到用户管理负责人排查</p>
<hr />
<h2 id="19024xx">用户请求错误 19024XX</h2>
<p>日志查询方法:</p>
<p>找到权限中心 SaaS 的 bk_iam-app.log 日志, 搜索对应的请求 request_id, 查询相关 api 调用的上下文</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/ErrorCodes_2.png" /></p>
<h3 id="1902403">1902403</h3>
<blockquote>
<p>app_code(bk_xxxx) do not be allowed to call api(group_list)</p>
</blockquote>
<p>需要添加白名单</p>
<blockquote>
<p>creator authorization instance api don't support the (xxxxx] of system[yyyyy]</p>
</blockquote>
<p>没有权限调用, 需要评估后, 添加白名单</p>
<blockquote>
<p>bad request:client(xxx) can not request system(yyy)</p>
</blockquote>
<p>不是该系统合法 clients</p>
<p>需要找系统权限模型的维护者, 在模型注册阶段, 将<code>app_code</code>加入到其系统合法<code>clients</code>列表中</p>
<h3 id="1902400-1902412-1902414-1902415-1902416">1902400 1902412 1902414 1902415 1902416</h3>
<p>描述: 用户的请求数据错误
说明: 请仔细阅读错误信息, 信息中包含具体原因 (如无法确定, 提供请求数据/结果返回数据/日志信息等提单到权限中心负责人排查)</p>
<blockquote>
<p>1902412 Parameter verification failed: related resource type(file_source), resource([ApplyPathNode(system_id='', type='file_source', id='53', name='')]) not satisfy instance selection"</p>
</blockquote>
<p>权限中心会校验请求中传递的资源列表, 是否与操作关联的<code>实例视图</code>链路匹配</p>
<h3 id="1902417">1902417</h3>
<p>描述: 权限提交的数据与接入系统注册操作依赖的资源类型数据校验错误</p>
<p>错误信息:</p>
<blockquote>
<p>action xxx has no related resource type yyy</p>
</blockquote>
<p>操作<code>xxx</code>不关联申请的资源类型<code>yyy</code></p>
<blockquote>
<p>action xxx related resource types yyy are in the wrong order</p>
</blockquote>
<p>操作<code>xxx</code>关联多个资源类型, 其中类型<code>yyy</code>与接入系统注册的操作关联资源类型顺序不一致</p>
<blockquote>
<p>action xxx lacks related resource type yyy</p>
</blockquote>
<p>操作<code>xxx</code>缺少资源类型<code>yyy</code></p>
<blockquote>
<p>Action check error: action <code>execute_script</code> related resource types <code>host</code> wrong</p>
</blockquote>
<p>传递的资源错误, 或者顺序与注册action的<code>releated_resource_types</code>顺序不一致</p>
<hr />
<h2 id="saas">附录: SaaS 错误码说明</h2>
<h3 id="1-api">1. 前端 api 调用错误时的提示</h3>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/ErrorCodes_3.png" /></p>
<p>当权限中心 SaaS 页面出现如上红框弹出提示时
表示
1. 回调接入系统接口失败
2. 权限中心 SaaS api 调用报错</p>
<p>点击复制, 可以获取的到报错详细信息, 根据信息分析原因</p>
<ol>
<li>如果是回调接入系统失败, 可以查看  <a href="Debug/SaaS-Callback.md">常见: SaaS 回调接入系统失败</a></li>
<li>如果是其他原因, 需要查看 api 返回的结果, 找到结果中的 code(错误码), 根据本页错误码索引确定原因</li>
</ol>
<h3 id="2-api-request_id">2. api 请求的 request_id</h3>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/ErrorCodes_4.png" /></p>
<p>权限中心 SaaS 的每个 api 请求都有 request_id, 在排查前记录 request_id, 在排查日志过程中可以更方便定位到错误信息</p>
<h3 id="3-api">3. api 返回结构说明</h3>
<pre class="codehilite"><code class="language-json">{
  &quot;code&quot;: 0,  // 返回code, 0表示成功, 其它为错误码
  &quot;data&quot;: [],
  &quot;message&quot;: &quot;OK&quot;,  // 返回的错误信息
  &quot;result&quot;: true  // 调用结果
}</code></pre><h1 id="_1">问题排查指引</h1>
<p>如果有<code>错误码</code>, 优先看错误码</p>
<ul>
<li><a href="ErrorCode.md">错误码</a></li>
</ul>
<p>如果是下面这几类问题, 直接跳转到对应文档</p>
<ul>
<li><a href="Debug/SaaS-Callback.md">常见: SaaS 回调接入系统失败</a></li>
<li><a href="Debug/SaaS-DeptSync.md">常见: SaaS 组织架构同步异常</a></li>
<li><a href="Debug/PolicyAPIDebug.md">常见: 为什么有权限/无权限</a></li>
</ul>
<hr />
<h2 id="1">1. 开发接入</h2>
<p>当遇到调用权限中心接口报错, 首先</p>
<ol>
<li>确认请求响应的 <a href="ErrorCode.md">错误码</a> 确认问题, 并根据指引解决</li>
<li>查找 FAQ</li>
<li>如果无法自助解决, 需要提单由权限中心开发协助排查, 请 <a href="Debug/Issue.md">提单模板</a> 提供环境/请求/响应等信息. 请务必按照要求填写, 便于更快速定位解决问题</li>
</ol>
<h2 id="2-saas">2. 使用权限中心 SaaS 过程中发现<code>未知错误</code></h2>
<p>客户在发现 SaaS 使用过程中出现 <code>未知错误</code> , 可以通过 <code>request_id</code> 查询到相关的调试信息, 提单时附加到单据中; </p>
<ul>
<li>如果配置权限回调接入系统报错, 根据 <a href="Debug/SaaS-Callback.md">回调接入系统失败</a></li>
<li>如果是组织架构同步异常/失败, 根据 <a href="Debug/SaaS-DeptSync.md">组织架构同步异常</a> 自助排查</li>
<li>可以根据 <a href="Debug/SelfHelp/SaaS-DebugTraceAPI.md">自助排查: SaaS 报错 Debug</a> 自助通过<code>request_id</code>获取报错详情;</li>
</ul>
<h2 id="3">3. 对权限有疑问</h2>
<p>鉴权接口正常返回, 但是不符合预期(为什么有权限/为什么无权限)</p>
<ol>
<li>到权限中心 SaaS 页面, 查看个人权限, 确认个人权限 / 组织架构权限 / 组权限 (大概率是继承了上级部门或所属组的权限)</li>
<li>想进一步从请求中确认权限计算细节; 可以根据 SDK 文档, 开启 debug 模式; 或者阅读 <a href="Debug/PolicyAPIDebug.md">鉴权接口 debug</a> 文档, 通过在请求参数中加<code>?debug=true</code>, 开启接口<code>debug</code>, 可以看到详细的策略计算流程; 如果怀疑是缓存问题, 可以加上<code>?force=true</code>参数, 强制走实时数据查询, 不走缓存;</li>
</ol>
<h2 id="4">4. 运维问题</h2>
<ol>
<li><a href="../OPS/Debug.md">确认权限中心服务是否可用？</a> </li>
</ol>
<h2 id="5">5. 进阶</h2>
<p>权限中心提供了 debug-cli, 用于深入定位一些复杂问题</p>
<p>用户可以</p>
<ol>
<li>根据文档指引中的问题排查步骤, 使用 debug-cli 获取信息</li>
<li>同权限中心开发协作, 共同排查生产问题</li>
<li>自行阅读文档, 自助排查问题</li>
</ol>
<p><a href="Debug/SelfHelp/DebugCLI.md">自助排查: IAM-Debug CLI</a> 使用文档</p><h1 id="_1">简介</h1>
<p>该教程将帮助你将业务的权限体系接入权限中心，通过该教程，你可以了解：
- 权限中心的基本模型和接入流程
- 使用 <code>python-sdk</code> 完成模型注册/鉴权</p>
<p>为了顺利完成教程，你需要：
- 了解权限中心基本模型及概念 <a href="../../权限中心/产品白皮书/术语解释/Trem.md">主要名词概念说明</a>
- 已部署一套可进行对接调试的权限中心
- 已经创建一个 SaaS 并获取其<code>bk_app_code</code>(应用 ID)和<code>bk_app_secret</code>(应用 TOKEN)
- 了解 Python 的基本语法(本教程基于 <code>python-sdk</code>)
- 教程中<code>{IAM_HOST}</code>指的是权限中心后台接口(注意是后台的地址, 例如<code>http://bkiam.service.consul:5001</code>, 不是前端页面的地址<code>http://{paas_domain}/o/bk_iam</code>). 本地开发环境可能无法访问到, 需要使用服务器访问, 或者由运维将后台服务地址反向代理给到本地开发访问. 通过企业版社区版 SaaS 部署的话, 可以通过<code>BK_IAM_V3_INNER_HOST</code>获取</p><h1 id="_1">准备工作</h1>
<h2 id="1">1. 应用创建</h2>
<p>开始教程前，你需要创建一个蓝鲸应用</p>
<p>如果是<code>非托管于蓝鲸PaaS</code>的<code>外部系统/平台或者应用</code>，可以通过 [蓝鲸智云]-[开发者中心]-[外链应用] 页面进行创建</p>
<p>如果是需要<code>托管于蓝鲸PaaS</code>的<code>SaaS应用或者S-mart应用</code>，可以通过 [蓝鲸智云]-[开发者中心]-[应用创建]页面进行创建(如果已经有对应应用，可以到[应用管理]-[基本信息]直接复制应用的<code>应用 ID</code>和<code>应用 TOKEN</code>)</p>
<p><img alt="enter image description here" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/QuickStart/image_2.png" /></p>
<p>应用创建后，在 [我的应用]-[应用管理]-[基本信息]可以找到<code>应用 ID</code>和<code>应用 TOKEN</code>，复制以便稍后接入使用.</p>
<p>这里假设是:</p>
<ul>
<li>bk_app_code: demo</li>
<li>bk_app_secret: c2cfbc92-28a2-420c-b567-cf7dc33cf29f</li>
</ul>
<p><img alt="enter image description here" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/QuickStart/image_3.png" /></p>
<h2 id="2">2. 了解基本接入流程</h2>
<p>大体接入流程:
1. 模型注册
2. 权限配置[在权限中心产品侧]
3. 实现鉴权
4. 实现无权限申请
5. 实现其他复杂场景: 关联操作/新建关联权限/获取有权限的资源列表</p>
<h2 id="3">3. 梳理系统权限模型</h2>
<ul>
<li>系统: <code>demo</code></li>
</ul>
<p>涉及的资源及权限以蓝鲸智云开发者中心为例</p>
<ul>
<li>资源: app(应用)</li>
<li>权限 1: 访问开发者中心. 管理类权限，与具体资源无关</li>
<li>权限 2: 开发 app. 有某个 app 的开发权限，与具体资源绑定</li>
</ul><h1 id="_1">模型注册</h1>
<p>注意:</p>
<ul>
<li>教程中<code>{IAM_HOST}</code>指的是权限中心后台接口(注意是后台的地址, 例如<code>http://bkiam.service.consul:5001</code>, 不是前端页面的地址<code>http://{paas_domain}/o/bk_iam</code>). 本地开发环境可能无法访问到, 需要使用服务器访问, 或者由运维将后台服务地址反向代理给到本地开发访问. 通过企业版社区版 SaaS 部署的话, 可以通过<code>BK_IAM_V3_INNER_HOST</code>获取</li>
</ul>
<h2 id="1">1. 注册系统</h2>
<p><a href="../Reference/API/02-Model/10-System.md">注册系统 API 文档</a></p>
<p>注意: <code>system_id</code>必须等于 app_code； </p>
<pre class="codehilite"><code class="language-bash">curl -XPOST 'http://{IAM_HOST}/api/v1/model/systems' \
-H 'X-Bk-App-Code: demo' \
-H 'X-Bk-App-Secret: c2cfbc92-28a2-420c-b567-cf7dc33cf29f' \
-H 'Content-Type: application/json' \
-d '{
    &quot;id&quot;: &quot;demo&quot;,
    &quot;name&quot;: &quot;Demo平台&quot;,
    &quot;name_en&quot;: &quot;Demo&quot;,
    &quot;description&quot;: &quot;A demo SaaS for quick start&quot;,
    &quot;description_en&quot;: &quot;A demo SaaS for quick start.&quot;,
    &quot;clients&quot;: &quot;demo&quot;,
    &quot;provider_config&quot;: {
        &quot;host&quot;: &quot;http://demo_callback_host&quot;,
        &quot;auth&quot;: &quot;basic&quot;,
        &quot;healthz&quot;: &quot;/healthz/&quot;
    }
}'</code></pre>


<h2 id="2">2. 注册资源类型</h2>
<p>某些权限会与具体的资源关联，在这里，<code>develop_app</code>开发应用的权限，跟具体的应用绑定； 整个 PaaS 平台可能有 100 个应用，但是某个人只有某几个应用的开发权限；</p>
<p><a href="../Reference/API/02-Model/11-ResourceType.md">注册资源类型 API 文档</a></p>
<pre class="codehilite"><code class="language-bash">curl -XPOST 'http://{IAM_HOST}/api/v1/model/systems/demo/resource-types' \
-H 'X-Bk-App-Code: demo' \
-H 'X-Bk-App-Secret: c2cfbc92-28a2-420c-b567-cf7dc33cf29f' \
-H 'Content-Type: application/json' \
-d '[
    {
        &quot;id&quot;: &quot;app&quot;,
        &quot;name&quot;: &quot;SaaS应用&quot;,
        &quot;name_en&quot;: &quot;application&quot;,
        &quot;description&quot;: &quot;SaaS应用&quot;,
        &quot;description_en&quot;: &quot;SaaS application&quot;,
        &quot;provider_config&quot;: {
            &quot;path&quot;: &quot;/iam/api/v1/resources/&quot;
        },
        &quot;version&quot;: 1
    }
]'</code></pre>


<h2 id="3">3. 注册实例视图</h2>
<p><a href="../Reference/API/02-Model/12-InstanceSelection.md">注册实例视图 API 文档</a></p>
<p>在配置<code>开发应用</code>权限的时候，由于这个操作关联了<code>应用</code>，所以需要配置<code>实例视图</code></p>
<ul>
<li><a href="../Reference/API/02-Model/00-Concepts.md">主要名词概念说明: 实例视图(instance_selections)</a></li>
<li><a href="../Explanation/01-instanceSelection.md">说明: 实例视图</a></li>
</ul>
<pre class="codehilite"><code class="language-bash">curl -XPOST 'http://{IAM_HOST}/api/v1/model/systems/demo/instance-selections' \
-H 'X-Bk-App-Code: demo' \
-H 'X-Bk-App-Secret: c2cfbc92-28a2-420c-b567-cf7dc33cf29f' \
-H 'Content-Type: application/json' \
-d '[
    {
        &quot;id&quot;: &quot;app_view&quot;,
        &quot;name&quot;: &quot;应用视图&quot;,
        &quot;name_en&quot;: &quot;app_view&quot;,
        &quot;resource_type_chain&quot;: [
            {
                &quot;system_id&quot;: &quot;demo&quot;,
                &quot;id&quot;: &quot;app&quot;
            }
        ]
    }
]'</code></pre>


<h2 id="3_1">3. 注册操作</h2>
<p><a href="../Reference/API/02-Model/13-Action.md">注册操作 API 文档</a></p>
<p>涉及两个操作，第一个操作<code>访问开发者中心</code>，第二个操作<code>开发应用</code></p>
<p>访问开发者中心(access_developer_center):
- 管理类权限
- 没有关联资源
- 没有依赖操作</p>
<p>开发应用(develop_app):
- 关联实例 <code>system_id=demo and id=app</code>(第 2 步注册的)
- 关联实例对应的选择视图是 <code>system_id=demo and id=app_view</code>(第 3 步注册的)
- 相关操作 <code>access_developer_center</code>，即申请<code>develop_app</code> 会一并申请 <code>access_developer_center</code>； (这样用户开发应用时，不需要单独再申请访问开发者中心的权限)</p>
<pre class="codehilite"><code class="language-bash">curl -XPOST 'http://{IAM_HOST}/api/v1/model/systems/demo/actions' \
-H 'X-Bk-App-Code: demo' \
-H 'X-Bk-App-Secret: c2cfbc92-28a2-420c-b567-cf7dc33cf29f' \
-H 'Content-Type: application/json' \
-d '[
    {
        &quot;id&quot;: &quot;access_developer_center&quot;,
        &quot;name&quot;: &quot;访问开发者中心&quot;,
        &quot;name_en&quot;: &quot;access developer center&quot;,
        &quot;description&quot;: &quot;一个用户是否能访问开发者中心&quot;,
        &quot;description_en&quot;: &quot;Is allowed to access the developer center&quot;,
        &quot;type&quot;: &quot;create&quot;,
        &quot;related_resource_types&quot;: [],
        &quot;version&quot;: 1
    },
    {
        &quot;id&quot;: &quot;develop_app&quot;,
        &quot;name&quot;: &quot;开发SaaS应用&quot;,
        &quot;name_en&quot;: &quot;develop app&quot;,
        &quot;description&quot;: &quot;一个用户是否能够开发SaaS&quot;,
        &quot;description_en&quot;: &quot;Is allowed to develop SaaS app&quot;,
        &quot;type&quot;: &quot;&quot;,
        &quot;related_actions&quot;: [
            &quot;access_developer_center&quot;
        ],
        &quot;related_resource_types&quot;: [
            {
                &quot;system_id&quot;: &quot;demo&quot;,
                &quot;id&quot;: &quot;app&quot;,
                &quot;name_alias&quot;: &quot;&quot;,
                &quot;name_alias_en&quot;: &quot;&quot;,
                &quot;related_instance_selections&quot;: [
                    {
                        &quot;system_id&quot;: &quot;demo&quot;,
                        &quot;id&quot;: &quot;app_view&quot;
                    }
                ]
            }
        ],
        &quot;version&quot;: 1
    }
]'</code></pre>


<h2 id="4">4. 查看注册模型的展示</h2>
<p>注册成功后，打开 [权限中心]-[权限申请]-[申请自定义权限]，可以看到刚才注册的模型</p>
<p>由于还没有实现 <a href="../Reference/API/03-Callback/01-API.md">资源反向拉取</a>，申请权限时，资源实例可以选择<code>无限制</code></p>
<p><img alt="enter image description here" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/QuickStart/image_4.png" /></p>
<p>如果实现了 <a href="../Reference/API/03-Callback/01-API.md">资源反向拉取</a>，申请权限时</p>
<p><img alt="enter image description here" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/QuickStart/image_7.jpg" /></p>
<p>如果勾选了右上角的<code>无限制</code>, 即所有应用的权限(包括现在及未来新建的应用)</p>
<p>实例选择是通过实例视图的配置展示的, 这里使用的实例视图是<code>app_view</code>(应用视图), 只配置了一级资源<code>system=demo, resource_type=app</code>, 所以回调接入系统拉取得到的是<code>应用列表</code></p>
<h2 id="5">5. 扩展阅读</h2>
<p>权限中心提供了另一种模型注册方式, 具体见 <a href="../HowTo/Solutions/Migration.md">权限模型自动初始化及更新 migration</a></p><h1 id="_1">鉴权</h1>
<p>注意:</p>
<ul>
<li>教程中<code>{IAM_HOST}</code>指的是权限中心后台接口(注意是后台的地址, 例如<code>http://bkiam.service.consul:5001</code>, 不是前端页面的地址<code>http://{paas_domain}/o/bk_iam</code>). 本地开发环境可能无法访问到, 需要使用服务器访问, 或者由运维将后台服务地址反向代理给到本地开发访问. 通过企业版社区版 SaaS 部署的话, 可以通过<code>BK_IAM_V3_INNER_HOST</code>获取</li>
</ul>
<h2 id="1-python-sdk">1. 使用 python sdk 进行鉴权</h2>
<p><a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/docs/usage.md#12-is_allowed">iam-python-sdk: is_allowed</a></p>
<pre class="codehilite"><code class="language-python">from iam import IAM, Request, Subject, Action, Resource


SYSTEM_ID = &quot;demo&quot;
APP_CODE = &quot;demo&quot;
APP_SECRET = &quot;c2cfbc92-28a2-420c-b567-cf7dc33cf29f&quot;
BK_IAM_HOST = &quot;http://{IAM_HOST}&quot;
BK_PAAS_HOST = ''


class Permission(object):
    def __init__(self):
        self._iam = IAM(APP_CODE, APP_SECRET, BK_IAM_HOST, BK_PAAS_HOST)

    def _make_request_without_resources(self, username, action_id):
        request = Request(
            SYSTEM_ID,
            Subject(&quot;user&quot;, username),
            Action(action_id),
            None,
            None,
        )
        return request

    def _make_request_with_resources(self, username, action_id, resources):
        request = Request(
            SYSTEM_ID,
            Subject(&quot;user&quot;, username),
            Action(action_id),
            resources,
            None,
        )
        return request

    def allowed_access_developer_center(self, username):
        &quot;&quot;&quot;
        访问开发者中心权限
        &quot;&quot;&quot;
        request = self._make_request_without_resources(username, &quot;access_developer_center&quot;)
        return self._iam.is_allowed(request)

    def allowed_develop_app(self, username, app_code):
        &quot;&quot;&quot;
        app开发权限
        &quot;&quot;&quot;
        r = Resource(SYSTEM_ID, 'app', app_code, {})
        resources = [r]
        request = self._make_request_with_resources(username, &quot;develop_app&quot;, resources)
        return self._iam.is_allowed(request)</code></pre>


<p>判定权限的地方</p>
<pre class="codehilite"><code class="language-python">Permission().allowed_access_developer_center(request.user.username)

Permission().allowed_develop_app(request.user.username, app_code)</code></pre>


<h2 id="2-api">2. 使用 API 进行鉴权</h2>
<p>访问开发者中心权限</p>
<pre class="codehilite"><code class="language-bash">curl -XPOST 'http://{IAM_HOST}/api/v1/policy/auth' \
-H 'X-Bk-App-Code: demo' \
-H 'X-Bk-App-Secret: c2cfbc92-28a2-420c-b567-cf7dc33cf29f' \
-H 'Content-Type: application/json' \
-d '{
    &quot;system&quot;: &quot;demo&quot;,
    &quot;subject&quot;: {
        &quot;type&quot;: &quot;user&quot;,
        &quot;id&quot;: &quot;tom&quot;
    },
    &quot;action&quot;: {
        &quot;id&quot;: &quot;access_developer_center&quot;
    },
    &quot;resources&quot;: []
}'

# response
{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: {
        &quot;allowed&quot;: true
    }
}</code></pre>


<p>APP 开发权限</p>
<pre class="codehilite"><code class="language-bash">curl -XPOST 'http://{IAM_HOST}/api/v1/policy/auth' \
-H 'X-Bk-App-Code: demo' \
-H 'X-Bk-App-Secret: c2cfbc92-28a2-420c-b567-cf7dc33cf29f' \
-H 'Content-Type: application/json' \
-d '{
    &quot;system&quot;: &quot;demo&quot;,
    &quot;subject&quot;: {
        &quot;type&quot;: &quot;user&quot;,
        &quot;id&quot;: &quot;tom&quot;
    },
    &quot;action&quot;: {
        &quot;id&quot;: &quot;develop_app&quot;
    },
    &quot;resources&quot;: [{
        &quot;system&quot;: &quot;demo&quot;,
        &quot;type&quot;: &quot;app&quot;,
        &quot;id&quot;: &quot;test_app_1&quot;
    }]
}'

# response
{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: {
        &quot;allowed&quot;: false
    }
}</code></pre><h1 id="_1">无权限申请</h1>
<p>具体的 <a href="../HowTo/Solutions/NoPermissionApply.md">无权限交互方案</a></p>
<p><img alt="enter image description here" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/QuickStart/image_5.png" /></p>
<p>在前端展示用户无权限的相关列表, 当用户点击<code>去申请</code>按钮时, 需要跳转到权限中心申请对应权限.</p>
<p>接入系统需要提前将相关数据到权限中心生成一个<code>权限申请URL</code>, 引导用户跳转过去申请对应权限. <a href="../Reference/API/05-Application/01-GenerateURL.md">生成无权限申请 URL</a></p>
<p>使用 sdk 实现</p>
<pre class="codehilite"><code class="language-python">from iam.apply.models import ActionWithoutResources, ActionWithResources, Application, RelatedResourceType
from iam.apply.models import ResourceInstance, ResourceNode

class Permission(object):
    def __init__(self):
        self._iam = IAM(APP_CODE, APP_SECRET, BK_IAM_HOST, BK_PAAS_HOST)

    def make_no_resource_application(self, action_id):
        # 1. make application
        action = ActionWithoutResources(action_id)
        actions = [action]

        application = Application(SYSTEM_ID, actions)
        return application

    def make_resource_application(self, action_id, resource_type, resource_id, resource_name):
        # 1. make application
        # 这里支持带层级的资源, 例如 biz: 1/set: 2/host: 3
        # 如果不带层级, list中只有对应资源实例
        instance = ResourceInstance([ResourceNode(resource_type, resource_id, resource_name)])
        # 同一个资源类型可以包含多个资源
        related_resource_type = RelatedResourceType(SYSTEM_ID, resource_type, [instance])
        action = ActionWithResources(action_id, [related_resource_type])

        actions = [action, ]
        application = Application(SYSTEM_ID, actions)
        return application

    def generate_apply_url(self, bk_token, application):
        &quot;&quot;&quot;
        处理无权限 - 跳转申请列表
        &quot;&quot;&quot;
        # 2. get url
        ok, message, url = self._iam.get_apply_url(application, bk_token)
        if not ok:
            logger.error(&quot;iam generate apply url fail: %s&quot;, message)
            return IAM_APP_URL
        return url

    # def generate_apply_url(self, bk_username, application):
    #     &quot;&quot;&quot;
    #     处理无权限 - 跳转申请列表, 使用bk_username
    #     &quot;&quot;&quot;
    #     # 2. get url
    #     ok, message, url = self._iam.get_apply_url(application, bk_username=bk_username)
    #     if not ok:
    #         logger.error(&quot;iam generate apply url fail: %s&quot;, message)
    #         return IAM_APP_URL
    #     return url</code></pre>


<p>使用</p>
<pre class="codehilite"><code class="language-python"># bk_token从cookie中获取, 测试时可以使用Chrome浏览器登录蓝鲸, F12, Application-Storage-Coolies复制bk_token
# 如果拿不到bk_token, 可以直接改成传递bk_username; 见上面代码块中被注释的方法
access_application = make_no_resource_application(&quot;access_developer_center&quot;)
url = Permission().generate_apply_url(bk_token, access_application)

# 开发app权限
app_application = Permission().make_resource_application(&quot;develop_app&quot;, &quot;app&quot;, &quot;saas_test&quot;, &quot;saas_test&quot;)
url = Permission().generate_apply_url(bk_token, app_application)</code></pre>


<p>点击跳转到权限中心申请对应的权限</p>
<p><img alt="enter image description here" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/QuickStart/image_6.png" /></p><p>阅读 <a href="../HowTo/Guide.md">接入指引</a></p><h1 id="1">样例 1: 无关联实例权限</h1>
<h2 id="1_1">1. 场景描述</h2>
<p>这类权限不关联任何实例, 属于<code>管理</code>类权限, 例如: 
- 能否访问某个入口, 例如能否访问开发者中心
- 是否是某个角色, 例如 管理员</p>
<h2 id="2">2. 权限分析</h2>
<ul>
<li>不关联任何实例</li>
<li>意味着,  只是单纯一个<code>操作</code></li>
<li>用户如果有权限, 那么权限中心会存在<code>用户-操作</code>的一条记录(如果查找不到, 代表用户没权限)</li>
</ul>
<h2 id="3">3. 权限模型</h2>
<ul>
<li>注意: 只需要注册一个<code>不关联任何resourceType</code>的<code>action</code>即可</li>
<li>即: <code>action</code> 的 <code>related_resource_types</code>为空列表<code>[]</code></li>
<li><a href="../../Reference/API/02-Model/13-Action.md">操作(Action) API</a></li>
</ul>
<pre class="codehilite"><code class="language-json">{
  &quot;id&quot;: &quot;access_developer_center&quot;,
  &quot;name&quot;: &quot;访问开发者中心&quot;,
  &quot;name_en&quot;: &quot;access developer center&quot;,
  &quot;description&quot;: &quot;一个用户是否能访问开发者中心&quot;,
  &quot;description_en&quot;: &quot;Is allowed to access the developer center&quot;,
  &quot;type&quot;: &quot;create&quot;,
  &quot;related_resource_types&quot;: [],
  &quot;version&quot;: 1
}</code></pre>


<ul>
<li>注册之后的权限配置页面</li>
</ul>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/01_01.jpg" /></p>
<h2 id="4">4. 鉴权</h2>
<h3 id="41-sdk">4.1 使用 SDK 进行鉴权</h3>
<pre class="codehilite"><code class="language-python">from iam import IAM, Request, Subject, Action, Resource


SYSTEM_ID = &quot;demo&quot;
APP_CODE = &quot;demo&quot;
APP_SECRET = &quot;c2cfbc92-28a2-420c-b567-cf7dc33cf29f&quot;
BK_IAM_HOST = &quot;http://{IAM_HOST}&quot;
BK_PAAS_HOST = ''


class Permission(object):
    def __init__(self):
        self._iam = IAM(APP_CODE, APP_SECRET, BK_IAM_HOST, BK_PAAS_HOST)

    def _make_request_without_resources(self, username, action_id):
        request = Request(
            SYSTEM_ID,
            Subject(&quot;user&quot;, username),
            Action(action_id),
            None,
            None,
        )
        return request

    def allowed_access_developer_center(self, username):
        &quot;&quot;&quot;
        访问开发者中心权限
        &quot;&quot;&quot;
        request = self._make_request_without_resources(username, &quot;access_developer_center&quot;)
        return self._iam.is_allowed(request)

# 使用
# Permission().allowed_access_developer_center(request.user.username)</code></pre>


<h3 id="42-api">4.2 使用直接鉴权 API 进行鉴权</h3>
<ul>
<li><a href="../../Reference/API/04-Auth/02-DirectAPI.md">直接鉴权 API: policy auth</a></li>
</ul>
<pre class="codehilite"><code class="language-bash">curl -XPOST 'http://{IAM_HOST}/api/v1/policy/auth' \
-H 'X-Bk-App-Code: demo' \
-H 'X-Bk-App-Secret: c2cfbc92-28a2-420c-b567-cf7dc33cf29f' \
-H 'Content-Type: application/json' \
-d '{
  &quot;action&quot;: {
    &quot;id&quot;: &quot;access_developer_center&quot;
  },
  &quot;system&quot;: &quot;demo&quot;,
  &quot;resources&quot;: [],
  &quot;subject&quot;: {
    &quot;type&quot;: &quot;user&quot;,
    &quot;id&quot;: &quot;testuser1&quot;
  }
}'


{
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;ok&quot;,
  &quot;data&quot;: {
    &quot;allowed&quot;: false
  }
}</code></pre>


<h2 id="5">5. 无权限申请</h2>
<p>在前端展示用户无权限的相关列表, 当用户点击<code>去申请</code>按钮时, 需要跳转到权限中心申请对应权限.</p>
<p>接入系统需要提前将相关数据到权限中心生成一个<code>权限申请URL</code>, 引导用户跳转过去申请对应权限. <a href="../../Reference/API/05-Application/01-GenerateURL.md">生成无权限申请 URL</a></p>
<p>具体的 <a href="../Solutions/NoPermissionApply.md">无权限交互方案</a></p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/01_02.jpg" /></p>
<pre class="codehilite"><code class="language-python">from iam.apply.models import ActionWithoutResources, ActionWithResources, Application, RelatedResourceType
from iam.apply.models import ResourceInstance, ResourceNode

class Permission(object):
    def __init__(self):
        self._iam = IAM(APP_CODE, APP_SECRET, BK_IAM_HOST, BK_PAAS_HOST)

    def make_no_resource_application(self, action_id):
        # 1. make application
        action = ActionWithoutResources(action_id)
        actions = [action]

        application = Application(SYSTEM_ID, actions)
        return application

    def generate_apply_url(self, bk_token, application):
        &quot;&quot;&quot;
        处理无权限 - 跳转申请列表
        &quot;&quot;&quot;
        # 2. get url
        ok, message, url = self._iam.get_apply_url(application, bk_token)
        if not ok:
            logger.error(&quot;iam generate apply url fail: %s&quot;, message)
            return IAM_APP_URL
        return url

# 使用        
# bk_token从cookie中获取, 测试时可以使用Chrome浏览器登录蓝鲸, F12, Application-Storage-Coolies复制bk_token
# access_application = make_no_resource_application(&quot;access_developer_center&quot;)
# url = Permission().generate_apply_url(bk_token, access_application)</code></pre><h1 id="2">样例 2: 关联简单实例权限</h1>
<h2 id="1">1. 场景描述</h2>
<p>这类权限关联简单的<code>实例</code>, 例如:
- 有没有某个应用的管理权限
- 有没有某个项目的查看权限</p>
<p>通常
- 适用于<code>个人-实例</code>数量不会太过的场景, 例如开发者中心的应用数量, 10 年大概是 2000 个
- 不适用于<code>个人-实例</code>数量很大的场景, 例如一个人拥有 100000 台主机的编辑权限, 此时不应该直接套用这个权限模型, 应该以更高维度来管理权限, 例如<code>业务-模块-主机</code>, 授予用户<code>业务下的所有主机权限</code>(只需要 1 条业务权限策略, 而不是 100000 条主机权限策略)  <a href="../../Explanation/06-LargeScaleInstances.md">大规模实例级权限限制</a>
- 如果<code>实例</code>数量是随着时间增长的, 做好数量评估, 例如作业平台的作业数量, 1 个人 10 年大概是 1000 个, 那么可以使用这个模型; 例如标准运维 task 执行, 每执行一次生成一个, 这个就不适用; 
- 原则: 尽量使用范围授权</p>
<h2 id="2_1">2. 权限分析</h2>
<ul>
<li>关联简单实例</li>
<li>注册一个<code>action</code>及对应的实例类型<code>resourceType</code></li>
<li>同时需要注册, 配置权限时如何勾选到实例的<code>实例视图</code>(<code>instanceSelections</code>)</li>
</ul>
<p>相关阅读:
- <a href="../../Explanation/01-instanceSelection.md">说明: 实例视图</a></p>
<h2 id="3">3. 权限模型</h2>
<ul>
<li>注册实例类型<code>resourceType</code></li>
</ul>
<pre class="codehilite"><code class="language-json">{
  &quot;id&quot;: &quot;app&quot;,
  &quot;name&quot;: &quot;SaaS应用及外链应用&quot;,
  &quot;name_en&quot;: &quot;application&quot;,
  &quot;description&quot;: &quot;SaaS应用及外链应用&quot;,
  &quot;description_en&quot;: &quot;SaaS application and ext-lint application&quot;,
  &quot;provider_config&quot;: {
    &quot;path&quot;: &quot;/iam/api/v1/resources/&quot;
  },
  &quot;version&quot;: 1
}</code></pre>


<ul>
<li>注册实例视图<code>instanceSelections</code></li>
</ul>
<pre class="codehilite"><code class="language-json">{
  &quot;id&quot;: &quot;app_view&quot;,
  &quot;name&quot;: &quot;应用视图&quot;,
  &quot;name_en&quot;: &quot;app_view&quot;,
  &quot;resource_type_chain&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_paas&quot;,
      &quot;id&quot;: &quot;app&quot;
    }
  ]
}</code></pre>


<ul>
<li>注册操作, 关联实例类型及实例视图</li>
</ul>
<pre class="codehilite"><code class="language-json">{
  &quot;id&quot;: &quot;develop_app&quot;,
  &quot;name&quot;: &quot;开发SaaS应用及外链应用&quot;,
  &quot;name_en&quot;: &quot;develop app&quot;,
  &quot;description&quot;: &quot;一个用户是否能够开发SaaS 及外链应用&quot;,
  &quot;description_en&quot;: &quot;Is allowed to develop SaaS app and ext-link app&quot;,
  &quot;type&quot;: &quot;&quot;,
  &quot;related_actions&quot;: [
    &quot;access_developer_center&quot;
  ],
  &quot;related_resource_types&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_paas&quot;,
      &quot;id&quot;: &quot;app&quot;,
      &quot;name_alias&quot;: &quot;&quot;,
      &quot;name_alias_en&quot;: &quot;&quot;,
      &quot;related_instance_selections&quot;: [
        {
          &quot;system_id&quot;: &quot;bk_paas&quot;,
          &quot;id&quot;: &quot;app_view&quot;
        }
      ]
    }
  ],
  &quot;version&quot;: 1
}</code></pre>


<ul>
<li>注册之后的权限配置页面</li>
</ul>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/02_01.jpg" /></p>
<h2 id="4">4. 鉴权</h2>
<h3 id="41-sdk">4.1 使用 sdk 进行鉴权</h3>
<pre class="codehilite"><code class="language-python">from iam import IAM, Request, Subject, Action, Resource


SYSTEM_ID = &quot;demo&quot;
APP_CODE = &quot;demo&quot;
APP_SECRET = &quot;c2cfbc92-28a2-420c-b567-cf7dc33cf29f&quot;
BK_IAM_HOST = &quot;http://{IAM_HOST}&quot;
BK_PAAS_HOST = ''


class Permission(object):
    def __init__(self):
        self._iam = IAM(APP_CODE, APP_SECRET, BK_IAM_HOST, BK_PAAS_HOST)

    def _make_request_with_resources(self, username, action_id, resources):
        request = Request(
            SYSTEM_ID,
            Subject(&quot;user&quot;, username),
            Action(action_id),
            resources,
            None,
        )
        return request

    def allowed_develop_app(self, username, app_code):
        &quot;&quot;&quot;
        app开发权限
        &quot;&quot;&quot;
        r = Resource(SYSTEM_ID, 'app', app_code, {})
        resources = [r]
        request = self._make_request_with_resources(username, &quot;develop_app&quot;, resources)
        return self._iam.is_allowed(request)

# 使用
# Permission().allowed_develop_app(request.user.username, app_code)</code></pre>


<h3 id="42-api">4.2 使用直接鉴权 API 进行鉴权</h3>
<ul>
<li><a href="../../Reference/API/04-Auth/02-DirectAPI.md">直接鉴权 API: policy auth</a></li>
</ul>
<pre class="codehilite"><code class="language-bash">curl -XPOST 'http://{IAM_HOST}/api/v1/policy/auth' \
-H 'X-Bk-App-Code: demo' \
-H 'X-Bk-App-Secret: c2cfbc92-28a2-420c-b567-cf7dc33cf29f' \
-H 'Content-Type: application/json' \
-d '{
  &quot;action&quot;: {
    &quot;id&quot;: &quot;access_developer_center&quot;
  },
  &quot;system&quot;: &quot;demo&quot;,
  &quot;resources&quot;: [
    {
      &quot;system&quot;: &quot;demo&quot;,
      &quot;type&quot;: &quot;app&quot;,
      &quot;id&quot;: &quot;test&quot;,
      &quot;attribute&quot;: {}
    }
  ],
  &quot;subject&quot;: {
    &quot;type&quot;: &quot;user&quot;,
    &quot;id&quot;: &quot;testuser1&quot;
  }
}'


{
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;ok&quot;,
  &quot;data&quot;: {
    &quot;allowed&quot;: false
  }
}</code></pre>


<h2 id="5">5. 无权限申请</h2>
<p>在前端展示用户无权限的相关列表, 当用户点击<code>去申请</code>按钮时, 需要跳转到权限中心申请对应权限.</p>
<p>接入系统需要提前将相关数据到权限中心生成一个<code>权限申请URL</code>, 引导用户跳转过去申请对应权限. <a href="../../Reference/API/05-Application/01-GenerateURL.md">生成无权限申请 URL</a></p>
<p>具体的 <a href="../Solutions/NoPermissionApply.md">无权限交互方案</a></p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/02_02.jpg" /></p>
<pre class="codehilite"><code class="language-python">from iam.apply.models import ActionWithoutResources, ActionWithResources, Application, RelatedResourceType
from iam.apply.models import ResourceInstance, ResourceNode

class Permission(object):
    def __init__(self):
        self._iam = IAM(APP_CODE, APP_SECRET, BK_IAM_HOST, BK_PAAS_HOST)

    def make_resource_application(self, action_id, resource_type, resource_id, resource_name):
        # 1. make application
        # 这里支持带层级的资源, 例如 biz: 1/set: 2/host: 3
        # 如果不带层级, list中只有对应资源实例
        instance = ResourceInstance([ResourceNode(resource_type, resource_id, resource_name)])
        # 同一个资源类型可以包含多个资源
        related_resource_type = RelatedResourceType(SYSTEM_ID, resource_type, [instance])
        action = ActionWithResources(action_id, [related_resource_type])

        actions = [action, ]
        application = Application(SYSTEM_ID, actions)
        return application

    def generate_apply_url(self, bk_token, application):
        &quot;&quot;&quot;
        处理无权限 - 跳转申请列表
        &quot;&quot;&quot;
        # 2. get url
        ok, message, url = self._iam.get_apply_url(application, bk_token)
        if not ok:
            logger.error(&quot;iam generate apply url fail: %s&quot;, message)
            return IAM_APP_URL
        return url

# 开发app权限
# app_application = Permission().make_resource_application(&quot;develop_app&quot;, &quot;app&quot;, &quot;saas_test&quot;, &quot;saas_test&quot;)
# url = Permission().generate_apply_url(bk_token, app_application)</code></pre><h1 id="3">样例 3: 使用拓扑层级管理权限</h1>
<h2 id="_1">相关阅读</h2>
<blockquote>
<p>拓扑层级管理权限涉及到实例视图的概念, 请先阅读相关的文档, 了解实例视图的概念</p>
</blockquote>
<ul>
<li><a href="../../Explanation/01-instanceSelection.md">说明: 实例视图</a></li>
<li><a href="../../Explanation/04-BkIAMPath.md">说明: 资源拓扑<code>_bk_iam_path_</code></a></li>
</ul>
<h2 id="1">1. 场景描述</h2>
<p>在业务实际模型中, 可能存在多层的<code>拓扑层级</code>关系, 例如<code>项目-模块-主机</code>.</p>
<p>此时, 配置<code>主机的查看权限</code>, 可以使用<code>拓扑层级</code>来配置</p>
<ul>
<li>项目 A 下的所有主机</li>
<li>项目 A-模块 B 下的所有主机</li>
<li>项目 A-模块 B-主机 C </li>
</ul>
<p>此时, 注册模型权限中心支持配置<code>实例视图</code>, 实例视图链路中的每种资源类型即拓扑层级的每一级资源类型; <code>project-module-host</code>; 在申请权限的时候, 可以根据需求, 使用上层关系授权, 或者使用实例级别授权;</p>
<h2 id="2">2. 权限分析</h2>
<p>样例以标准云运维的<code>流程查看</code>为例, 其拓扑层级关系是<code>项目-流程模板</code></p>
<ul>
<li>需要注册资源类型 流程模板 <code>flow</code></li>
<li>需要注册资源类型 项目 <code>project</code></li>
<li>注册实例视图, 声明 <code>flow</code>实例的选择方式,  实例视图<code>instanceSelection=flow</code>,  是拓扑层级的关系, <code>project-flow</code></li>
<li>注册操作  <code>flow_view</code><ul>
<li>关联实例类型 <code>resourceType=flow</code></li>
<li>关联资源的实例视图 <code>flow.related_instance_selections=flow</code></li>
</ul>
</li>
</ul>
<h2 id="3_1">3. 权限模型</h2>
<p>注册资源类型<code>project</code>和<code>flow</code>, 注意<code>flow</code>的拓扑层级的父级是<code>project</code>; 即, <code>项目/流程模板</code></p>
<pre class="codehilite"><code class="language-json">{
  &quot;id&quot;: &quot;project&quot;,
  &quot;name&quot;: &quot;项目&quot;,
  &quot;name_en&quot;: &quot;project&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;description_en&quot;: &quot;&quot;,
  &quot;parents&quot;: [],
  &quot;provider_config&quot;: {
    &quot;path&quot;: &quot;/iam/resource/api/v1/&quot;
  },
  &quot;version&quot;: 1
}


{
  &quot;id&quot;: &quot;flow&quot;,
  &quot;name&quot;: &quot;流程模板&quot;,
  &quot;name_en&quot;: &quot;flow&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;description_en&quot;: &quot;&quot;,
  &quot;parents&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;project&quot;
    }
  ],
  &quot;provider_config&quot;: {
    &quot;path&quot;: &quot;/iam/resource/api/v1/&quot;
  },
  &quot;version&quot;: 1
}</code></pre>


<p>配置实例视图<code>flow</code>(决定了配置权限时, 如何选到 flow), 拓扑层级关系是, 选择<code>project</code>下的<code>flow</code></p>
<pre class="codehilite"><code class="language-json">{
  &quot;id&quot;: &quot;flow&quot;,
  &quot;name&quot;: &quot;流程模板&quot;,
  &quot;name_en&quot;: &quot;Flow&quot;,
  &quot;resource_type_chain&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;project&quot;
    },
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;flow&quot;
    }
  ]
}</code></pre>


<p>注册操作<code>流程查看</code>, 关联资源类型 <code>flow</code>, 资源类型的 实例视图 <code>related_instance_selections</code> 是 <code>flow</code></p>
<pre class="codehilite"><code class="language-json">{
  &quot;id&quot;: &quot;flow_view&quot;,
  &quot;name&quot;: &quot;流程查看&quot;,
  &quot;name_en&quot;: &quot;Flow View&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;description_en&quot;: &quot;&quot;,
  &quot;type&quot;: &quot;view&quot;,
  &quot;related_resource_types&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;flow&quot;,
      &quot;related_instance_selections&quot;: [
        {
          &quot;system_id&quot;: &quot;bk_sops&quot;,
          &quot;id&quot;: &quot;flow&quot;
        }
      ]
    }
  ],
  &quot;version&quot;: 1
}</code></pre>


<p>这样, 配置权限时, 实例视图中选择 flow 就会存在树状结构, 上级是<code>project</code>, 叶子节点是<code>flow</code>;</p>
<ul>
<li>如果勾选了<code>project</code>, 代表这个项目下的所有流程模板有权限; <ul>
<li>生成策略: <code>__bk_iam_path__ startswith /project,123/</code></li>
</ul>
</li>
<li>如果勾选了具体某个<code>flow</code>, 代表仅对某个项目下这个具体的流程模板有权限;<ul>
<li>生成策略: <code>__bk_iam_path__ startswith /project,123/ AND flow.id eq "abc"</code></li>
</ul>
</li>
</ul>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/03_01.jpg" /></p>
<h2 id="4">4. 鉴权</h2>
<p>需要注意, Resource 传递 attribute 中包含一个字段<code>__bk_iam_path__</code>, 这个字段格式具体查看  <a href="../../Explanation/04-BkIAMPath.md">说明: 资源拓扑<code>_bk_iam_path_</code></a></p>
<p><code>/project,abc/</code>代表<code>task 123</code>是<code>project abc</code>下的一个流程.</p>
<pre class="codehilite"><code class="language-bash">[
        Resource(
            &quot;bk_sops&quot;,
            &quot;task&quot;,
            123,
            {
                &quot;iam_resource_owner&quot;: &quot;tom&quot;,
                &quot;_bk_iam_path_&quot;: [&quot;/project,abc/&quot;],
                &quot;name&quot;: &quot;test_task&quot;,
                &quot;type&quot;: &quot;flow&quot;
            },
        )
    ]</code></pre>


<h2 id="5">5. 无权限申请</h2>
<p><a href="../../Reference/API/05-Application/01-GenerateURL.md">生成无权限申请 URL</a>中, 使用<code>instances</code>进行拓扑层级的权限申请; </p>
<p>例如
- <code>instances[0]</code>中的<code>resources</code>列表只包含了<code>project=a</code>, 代表申请<code>project a</code>下的所有<code>flow</code>的查看权限; 
- 如果包含了<code>project=a, flow=b</code>,   代表申请<code>project a</code>下的<code>flow b</code>的查看权限;</p><h1 id="4">样例 4: 使用属性管理权限</h1>
<h2 id="1">1. 场景描述</h2>
<p>使用属性来进行授权, 可以达到<code>范围授权</code>的目的, 即, 通过<code>资源的属性</code>进行权限管理.</p>
<p>例如:
- 主机有一个分类属性, <code>type=db</code>表示数据库主机, <code>type=redis</code>表示 redis 主机
- 可以配置查看权限, 使用 <code>type=db</code>, 则用户拥有所有<code>type=db</code>的主机的查看权限; </p>
<p>注意, 这个属性指的是<code>资源属性</code>, 鉴权的时候, 需要带上相应的属性<code>key-value</code></p>
<h2 id="2">2. 权限分析</h2>
<p>这个样例中, 我们以标准运维的任务查看为例, 任务查看支持属性授权; </p>
<ul>
<li>有一个资源类型<code>task</code></li>
<li>task 拥有两个属性用于权限配置 1. type 任务类型 2. iam_resource_owner 资源创建者</li>
<li>操作<code>task_view</code>任务查看, 支持使用属性配置权限</li>
</ul>
<h2 id="3">3. 权限模型</h2>
<p>注册操作</p>
<p>注意, 操作的<code>task_view</code>关联的资源类型是<code>task</code>, 其<code>selection_mode=all</code> 表示, 同时支持使用 <code>选择实例</code>和<code>配置属性</code>;</p>
<p>即, 支持使用属性授权</p>
<pre class="codehilite"><code class="language-json">{
  &quot;id&quot;: &quot;task_view&quot;,
  &quot;name&quot;: &quot;任务查看&quot;,
  &quot;name_en&quot;: &quot;Task View&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;description_en&quot;: &quot;&quot;,
  &quot;type&quot;: &quot;view&quot;,
  &quot;related_resource_types&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;task&quot;,
      &quot;selection_mode&quot;: &quot;all&quot;,
      &quot;related_instance_selections&quot;: [
        {
          &quot;system_id&quot;: &quot;bk_sops&quot;,
          &quot;id&quot;: &quot;task&quot;
        }
      ]
    }
  ],
  &quot;version&quot;: 1
}</code></pre>


<p>此时产品页面的申请入口, 配置页面回调了 <a href="../../Reference/API/03-Callback/01-API.md">资源反向拉取 API</a>中的<code>list_attr</code>和<code>list_attr_value</code>(即接入系统如果配置了属性, 需要实现相应的回调接口)</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/04_01.jpg" /></p>
<h2 id="4_1">4. 鉴权</h2>
<p>鉴权逻辑同 <a href="./02-ActionWithResource.md">样例 2: 关联简单实例权限</a> 一致, 只是鉴权参数中, resource 需要带上 <code>attribute</code> 字典; </p>
<pre class="codehilite"><code class="language-python">r = Resource(SYSTEM_ID, 'app', app_code, {&quot;iam_resource_owner&quot;: &quot;tom&quot;})</code></pre>


<h2 id="5">5. 无权限申请</h2>
<p>逻辑同 <a href="./02-ActionWithResource.md">样例 2: 关联简单实例权限</a> 一致</p>
<p><a href="../../Reference/API/05-Application/01-GenerateURL.md">生成无权限申请 URL</a> 协议中, 申请属性授权, 配置的是<code>attributes</code>字段</p><h1 id="5">样例 5: 配置操作组优化权限申请</h1>
<h2 id="1">1. 场景描述</h2>
<p>一般情况下, 单个系统的权限可能有多个操作, 甚至几十个操作;</p>
<p>如果没有分类, 用户在申请时, 难以找到目标的操作;</p>
<p>权限中心提供了<code>操作组</code>, 支持接入系统将操作进行分类, 划分到不同组中, 这样在申请页面, 操作将以接入系统配置的分类进行展示, 体验更好.</p>
<h2 id="2">2. 权限模型</h2>
<p>通过 <a href="../../Reference/API/02-Model/14-ActionGroup.md">操作组(ActionGroup) API</a> 进行注册;</p>
<p>例如 bk_paas 存在 5 个操作, 可以划分成三类.</p>
<pre class="codehilite"><code class="language-json">[
  {
    &quot;name&quot;: &quot;访问权限&quot;,
    &quot;name_en&quot;: &quot;Access Permissions&quot;,
    &quot;actions&quot;: [
      {
        &quot;id&quot;: &quot;access_developer_center&quot;
      }
    ]
  },
  {
    &quot;name&quot;: &quot;开发者权限&quot;,
    &quot;name_en&quot;: &quot;Developer Permissions&quot;,
    &quot;actions&quot;: [
      {
        &quot;id&quot;: &quot;develop_app&quot;
      }
    ]
  },
  {
    &quot;name&quot;: &quot;管理权限&quot;,
    &quot;name_en&quot;: &quot;Admin Permissions&quot;,
    &quot;actions&quot;: [
      {
        &quot;id&quot;: &quot;manage_smart&quot;
      },
      {
        &quot;id&quot;: &quot;ops_system&quot;
      },
      {
        &quot;id&quot;: &quot;manage_apigateway&quot;
      }
    ]
  }
]</code></pre>


<h2 id="3">3. 产品交互</h2>
<p>在权限申请页面, 自动根据注册的配置, 将权限分成了<code>访问权限</code>/<code>开发者权限</code>/<code>管理权限</code>三组;</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/05_01.jpg" /></p><h1 id="6">样例 6: 配置常用操作优化权限申请</h1>
<h2 id="1">1. 场景描述</h2>
<p>在用户使用系统的时候, 为了完成某些事情, 需要申请<code>一批操作的权限</code>, 为了避免让用户自己一个个去申请, 或者申请过程中漏掉某些权限</p>
<p>接入系统可以将<code>一批操作</code>配置成<code>常用操作</code></p>
<p>这样, 在申请页面, 用户通过点击<code>常用操作</code>, 可以快速批量勾选一批操作进行权限申请</p>
<h2 id="2">2. 权限模型</h2>
<p>通过 <a href="../../Reference/API/02-Model/17-CommonActions.md">常用操作配置(CommonActions) API</a> 进行注册</p>
<p>例如标准运维的常用操作<code>使用流程创建任务</code> 关联了 3 个操作</p>
<pre class="codehilite"><code class="language-json">[
  {
    &quot;name&quot;: &quot;使用流程创建任务&quot;,
    &quot;name_en&quot;: &quot;Create task by flow&quot;,
    &quot;actions&quot;: [
      {
        &quot;id&quot;: &quot;project_view&quot;
      },
      {
        &quot;id&quot;: &quot;flow_view&quot;
      },
      {
        &quot;id&quot;: &quot;flow_create_task&quot;
      }
    ]
  },
  {
    &quot;name&quot;: &quot;使用轻应用&quot;,
    &quot;name_en&quot;: &quot;Use mini app&quot;,
    &quot;actions&quot;: [
      {
        &quot;id&quot;: &quot;project_view&quot;
      },
      {
        &quot;id&quot;: &quot;flow_view&quot;
      },
      {
        &quot;id&quot;: &quot;mini_app_view&quot;
      },
      {
        &quot;id&quot;: &quot;mini_app_create_task&quot;
      }
    ]
  },
  {
    &quot;name&quot;: &quot;使用公共流程创建任务&quot;,
    &quot;name_en&quot;: &quot;Create task by common flow&quot;,
    &quot;actions&quot;: [
      {
        &quot;id&quot;: &quot;project_view&quot;
      },
      {
        &quot;id&quot;: &quot;common_flow_view&quot;
      },
      {
        &quot;id&quot;: &quot;common_flow_create_task&quot;
      }
    ]
  }
]</code></pre>


<h2 id="3">3. 产品交互</h2>
<p>在权限申请页面, 将会有个<code>推荐权限</code>区域, 里面是接入系统注册进来的<code>常用操作</code></p>
<p>选中某个常用操作时, 会勾选对应的<code>操作列表</code>中的所有操作;</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/06_01.jpg" /></p><h1 id="7">样例 7: 配置依赖操作优化权限申请</h1>
<h2 id="1">1. 场景描述</h2>
<p>依赖操作，当用户申请的操作权限必须依赖其他操作权限（暂不支持跨系统操作关联）时，比如用户申请 作业编辑，必须依赖 作业查看 的操作权限，作业查看 就是 作业编辑 的依赖操作。</p>
<p>在产品层表现就是：当用户勾选 作业编辑 时，系统在创建申请单时，会自动申请 作业查看 权限。</p>
<p>更多的例子:
- 申请某个应用的开发者权限, 自动申请访问开发者中心的权限
- 申请某个项目的编辑权限, 自动申请项目的查看权限</p>
<p>有了依赖操作, 就可以一次性将权限申请到, 不会出现<code>申请到编辑权限</code>, 具体到编辑页的时候, 发现没有<code>查看权限</code>需要再次申请的问题;</p>
<h2 id="2">2. 权限模型</h2>
<p>在注册 action 的时候, 配置其<code>related_actions</code></p>
<p>例如在<code>样例2: 关联简单实例权限</code>, 注册<code>开发应用</code>的关联操作是<code>访问开发者中心</code>; 即, 申请某个应用的开发权限, 就能访问开发者中心, 不需要额外处理;</p>
<p>注册操作<code>develop_app</code>的<code>related_actions=["access_developer_center"]</code></p>
<pre class="codehilite"><code class="language-json">{
  &quot;id&quot;: &quot;develop_app&quot;,
   ......
  &quot;related_actions&quot;: [
    &quot;access_developer_center&quot;
  ],
   ......
}</code></pre>


<h2 id="3">3. 产品交互</h2>
<p>申请某个应用的开发权限</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/07_01.jpg" /></p>
<p>点击<code>提交</code>后, 会生成权限申请单; </p>
<p>可以看到, 申请单中, 多了<code>访问开发者中心</code></p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/07_02.jpg" /></p><h1 id="8">样例 8: 系统间调用无权限申请</h1>
<h2 id="1">1. 场景描述</h2>
<p>用户在使用 A 系统的功能, A 系统需要以用户的身份调用 B 系统的 API, B 系统检查发现用户没有权限; </p>
<p>此时, B 系统需要将<code>用户需要在B系统申请的权限信息</code>返回给 A 系统 <a href="../../Reference/API/05-Application/02-NoPermissionData.md">第三方鉴权失败返回权限申请数据协议</a></p>
<p>然后页面上展示给用户, 通过 <a href="../../Reference/API/05-Application/01-GenerateURL.md">生成无权限申请 URL</a> 生成权限申请 URL, 用户点击跳转到权限中心申请权限</p>
<h2 id="2">2. 权限分析</h2>
<ul>
<li>B 系统接口无权限, 按照 <a href="../../Reference/API/05-Application/02-NoPermissionData.md">第三方鉴权失败返回权限申请数据协议</a> 返回数据, 需要注意填充<code>name</code>(调用方拿到要在页面展示的)</li>
<li>A 系统将返回数据组织, 在页面展示 <a href="../Solutions/NoPermissionApply.md">无权限交互方案</a>, 此时<code>系统</code>这一列是<code>B</code></li>
<li>A 系统将返回数据 <a href="../../Reference/API/05-Application/01-GenerateURL.md">生成无权限申请 URL</a> 生成权限申请 URL</li>
<li>用户点击按钮, 跳往权限中心, 申请<code>B</code>系统的权限</li>
</ul>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/08_01.jpg" /></p><h1 id="_1">开源项目: 接入权限中心的实现</h1>
<p>注意, 以下项目, 每个项目有各自的业务场景, 所以权限模型有简单也有复杂的, 可以参考其模型和实现, 并配合企业版/社区版的权限配置页面和产品交互了解到最终实现的权限形态; 应该了解并思考自身产品的权限模型, 切忌<code>生搬硬套</code></p>
<h2 id="tencentbk-paaspython">Tencent/bk-PaaS(python)</h2>
<ul>
<li>Github 地址: <a href="https://github.com/Tencent/bk-PaaS/tree/develop/paas2/paas">Tencent/bk-PaaS: develop</a><ul>
<li>对 iam 调用的封装: <a href="https://github.com/Tencent/bk-PaaS/blob/develop/paas2/paas/common/bk_iam.py">common/bk_iam.py</a></li>
</ul>
</li>
</ul>
<h2 id="tencentbk-sopspython">Tencent/bk-sops(python)</h2>
<ul>
<li>Github 地址: <a href="https://github.com/Tencent/bk-sops">Tencent/bk-sops</a><ul>
<li>权限模型: <a href="https://github.com/Tencent/bk-sops/tree/V3.6.X/support-files/iam">support-files/iam</a></li>
<li>对 iam 调用的封装: <a href="https://github.com/Tencent/bk-sops/tree/V3.6.X/gcloud/iam_auth">gcloud/iam_auth</a></li>
</ul>
</li>
</ul>
<h2 id="tencentbk-bcs-saaspython">Tencent/bk-bcs-saas(python)</h2>
<ul>
<li>Github 地址: <a href="https://github.com/Tencent/bk-bcs-saas">Tencent/bk-bcs-saas</a><ul>
<li>权限模型: <a href="https://github.com/Tencent/bk-bcs-saas/tree/master/bcs-app/support-files/iam">bcs-app/support-files/iam</a></li>
<li>对 iam 调用的封装: <a href="https://github.com/Tencent/bk-bcs-saas/tree/master/bcs-app/backend/iam">bcs-app/backend/iam</a></li>
</ul>
</li>
</ul>
<h2 id="tencentbluekingbk-itsmpython">TencentBlueKing/bk-itsm(python)</h2>
<ul>
<li>Github 地址: <a href="https://github.com/TencentBlueKing/bk-itsm">TencentBlueKing/bk-itsm</a><ul>
<li>对 iam 调用的封装: <a href="https://github.com/TencentBlueKing/bk-itsm/tree/master/itsm/auth_iam">itsm/auth_iam</a></li>
</ul>
</li>
</ul>
<h2 id="tencentbluekingbk-userpython">TencentBlueKing/bk-user(python)</h2>
<ul>
<li>Github 地址: <a href="https://github.com/TencentBlueKing/bk-user">TencentBlueKing/bk-user</a><ul>
<li>对 iam 调用的封装: <a href="https://github.com/TencentBlueKing/bk-user/tree/master/src/api/bkuser_core/bkiam">src/api/bkuser_core/bkiam</a></li>
</ul>
</li>
</ul>
<h2 id="tencentbluekingbk-logpython">TencentBlueKing/bk-log(python)</h2>
<ul>
<li>Github 地址: <a href="https://github.com/TencentBlueKing/bk-log">TencentBlueKing/bk-log</a><ul>
<li>对 iam 调用的封装: <a href="https://github.com/TencentBlueKing/bk-log/tree/master/apps/iam">apps/iam</a></li>
</ul>
</li>
</ul>
<h2 id="tencentbluekingbk-nodemanpython">TencentBlueKing/bk-nodeman(python)</h2>
<ul>
<li>Github 地址: <a href="https://github.com/TencentBlueKing/bk-nodeman">TencentBlueKing/bk-nodeman</a><ul>
<li>对 iam 调用的封装: <a href="https://github.com/TencentBlueKing/bk-nodeman/blob/V2.1.X/apps/node_man/handlers/iam.py">apps/node_man/handlers/iam.py</a></li>
</ul>
</li>
</ul>
<h2 id="tencentbk-jobjava">Tencent/bk-job(java)</h2>
<ul>
<li>Github 地址: <a href="https://github.com/Tencent/bk-job">Tencent/bk-job</a><ul>
<li>对 iam 调用的封装: <a href="https://github.com/Tencent/bk-job/tree/master/src/backend/commons/common-iam/src/main/java/com/tencent/bk/job/common/iam">src/backend/commons/common-iam/src/main/java/com/tencent/bk/job/common/iam</a></li>
</ul>
</li>
</ul><h1 id="_1">无权限交互方案</h1>
<h2 id="_2">无权限交互说明</h2>
<p>1、无权限校验尽量<strong>事前校验</strong>（用户点击资源操作前就提示有无权限），其次才事后校验（用户点击后才提示有无权限）。设计稿如下：</p>
<p><img alt="图片描述#600px" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/NoPermission_1.png" /></p>
<p>2、权限中心提供 api 和页面跳转方式支持无权限的交互，两种交互都需要系统提供具体的无权限的资源、资源实例、需要用户申请的权限。</p>
<ul>
<li>系统内资源无权限时，交互如下。</li>
</ul>
<p><img alt="图片描述#600px" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/NoPermission_2.png" /></p>
<ul>
<li>系统间调用无权限时（比如标准运维调作业平台），底层系统需要提供具体无权限数据（被调用系统、无权限的资源/资源实例、无权限的操作）给上层调用方系统，调用方系统进行无权限交互展示，用户点击交互如下。</li>
</ul>
<p><img alt="图片描述#600px" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/NoPermission_3.png" /></p>
<p>3、无权限时去权限中心申请，需在<strong>新标签页中打开权限中心的跳转链接</strong>，不在本地打开，否则会打断当前页面的操作。</p>
<p>4、如果是在已有弹窗的交互上提示无权限，采用<strong>二次遮罩效果（再弹窗）</strong>处理。</p>
<p>5、用户拥有某个系统的业务权限，不代表在其他系统拥有相同的业务权限。比如用户在配置平台可以看到 10 个业务，但是在作业平台可能看不到任何业务。</p>
<p>6、普通用户进入系统页面无任何权限时，整个页面提示用户<strong>暂无任何权限</strong>，用户只需要<strong>申请指定资源所属下任何一个资源的任何一个操作权限</strong>，审批通过后，可以查看具体系统页面。考虑到用户体验，系统可以根据自己的访问逻辑引导用户申请具体的初始权限。</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/NoPermission_8.png" /></p>
<p>7、用户点击「去申请」后，新窗口打开权限中心页面，将无权限相关数据传递给权限中心，权限中心参考「自定义申请页面交互样式」的基础上，需要让用户感知到新实例/新权限。</p>
<p><img alt="图片描述#600px" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/NoPermission_4.png" /></p>
<p>8、用户点击「去申请」后，SaaS 侧需要关闭当前弹窗，同时弹出「刷新页面」提醒。</p>
<p><img alt="图片描述#600px" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/NoPermission_5.png" /></p>
<h2 id="_3">无权限交互展示方案</h2>
<ul>
<li>方案一场景：</li>
</ul>
<p>当资源操作为角色/岗位类功能时，比如管理员页面，不给用户展示，表示的是这类资源操作非人人都可用 ，用户只能通过权限申请或者管理员授权获得相应的权限，这类资源操作对用户直接隐藏。</p>
<p><img alt="图片描述#600px" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/NoPermission_6.png" /></p>
<blockquote>
<p>注：普通用户通过链接访问无权限功能页面时，需提示用户无权限，交互设计如下。</p>
</blockquote>
<p><img alt="图片描述#600px" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/NoPermission_7.png" /></p>
<ul>
<li>方案二场景：</li>
</ul>
<p>当资源操作为具体细节功能点时，比如作业的新建、编辑、删除，表示的是这类资源操作 人人都可用 ，只是有无权限的区别，用户可以通过点击无权限的资源操作去申请具体的权限，这类资源操作对用户在显示样式上置灰处理，表示无权限访问该资源。</p><h1 id="migration">权限模型自动初始化及更新 migration</h1>
<blockquote>
<p>由于开发需求的不断迭代，系统的权限模型也会有一定修改，建议使用 Migration 的方式来执行权限模型变更</p>
</blockquote>
<p>附件:</p>
<ol>
<li><a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/iam/contrib/iam_migration/utils/do_migrate.py">do_migrate.py</a> 是届时给运维用的工具, 每个接入系统的模型接入可以写好对应 migration 文件后, 用这个文件先进行测试</li>
<li><a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/iam/contrib/iam_migration/utils/example.json">example.json</a> 是一个 migration 文件示例, 可以参考编辑自己系统的 migration 文件</li>
</ol>
<p>注意:</p>
<ul>
<li><code>do_migrate.py</code> 已交付 <a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/iam/contrib/iam_migration/utils/do_migrate.py">do_migrate.py</a></li>
<li><code>do_validate.py</code> 暂未实现, coming soon</li>
</ul>
<h2 id="1-migration">1. Migration 命令</h2>
<pre class="codehilite"><code class="language-shell"># 校验json文件是否合法? 只有合法的文件才提交到代码库
python  do_validate.py 0001_bk_paas_20190619-1632_iam.json

# 执行migrate
python do_migrate.py -h

python do_migrate.py -t http://bkiam.service.consul -f 0001_bk_paas_20190619-1632_iam.json -a {app_code} -s {app_secret}

# 如果环境中存在 APIGateway, 使用统一的 APIGateway 上的bk-iam网关进行注册; env值 prod(生产)/stage(预发布)
python do_migrate.py -t http://bk-iam.{APIGATEWAY_DOMAIN}/{env} -f 0001_bk_paas_20190619-1632_iam.json -a {app_code} -s {app_secret} --apigateway</code></pre>


<ul>
<li><code>{app_code} / {app_secret}</code> 为应用在 IAM 接入系统对应环境的<code>{app_code}/{app_secret}</code></li>
<li>do_migrate.py 执行依赖 python 环境 <code>requests</code>包</li>
<li>do_validate.py 执行依赖 python 环境<code>jsonschema</code>包
`</li>
</ul>
<h2 id="2-migration">2. Migration 文件</h2>
<h3 id="_1">存放目录</h3>
<p>工程目录下 <code>support-files/bkiam/</code></p>
<h3 id="_2">文件命名规则</h3>
<p><code>{序号}_{APP_CODE}_{时间戳}_iam.json</code></p>
<p>具体：
- 序号: 由 4 位数字组成, 从 1 开始, 不足 4 位, 高位用 0 补全, 如: 0001
- APP_CODE: 应用或平台的唯一 ID
- 时间戳: 该文件的创建时间, 格式为: YYYYmmdd-HHMM</p>
<p>示例：</p>
<pre class="codehilite"><code class="language-bash">0001_bk_paas_20190619-1632_iam.json
0002_bk_paas_20190620-1000_iam.json
0001_bk_job_20190620-2040_iam.json
0001_bk_cmdb_20190619-1020_iam.json</code></pre>


<h2 id="3-migration">3. Migration 内容规范</h2>
<p>json 文件格式</p>
<pre class="codehilite"><code class="language-bash">{
    &quot;system_id&quot;: &quot;bk_paas&quot;,
    &quot;operations&quot;: [
    {
            &quot;operation&quot;: &quot;[操作代码]&quot;,
            &quot;data&quot;:{
                 # 数据
            }
    }
}</code></pre>


<p>当前支持的操作代码</p>
<table>
<thead>
<tr>
<th align="left">操作代码</th>
<th align="left">data 类型(链接文档)</th>
<th align="left">行为</th>
<th align="left">注意</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">upsert_system</td>
<td align="left">Map,<a href="../../Reference/API/02-Model/10-System.md">格式</a></td>
<td align="left">新增或更新 system</td>
<td align="left"><strong>推荐</strong></td>
</tr>
<tr>
<td align="left">add_system</td>
<td align="left">同上</td>
<td align="left">新增 system</td>
<td align="left">当 system 已存在时将新增失败</td>
</tr>
<tr>
<td align="left">update_system</td>
<td align="left">同上</td>
<td align="left">更新系统</td>
<td align="left">不存在时将更新失败</td>
</tr>
<tr>
<td align="left">upsert_resource_type</td>
<td align="left">Map, <a href="../../Reference/API/02-Model/11-ResourceType.md">格式</a></td>
<td align="left">新增或更新 resource_type</td>
<td align="left"><strong>推荐</strong></td>
</tr>
<tr>
<td align="left">add_resource_type</td>
<td align="left">同上</td>
<td align="left">新增 resource_type</td>
<td align="left">当 resource_type 已存在时将新增失败</td>
</tr>
<tr>
<td align="left">update_resource_type</td>
<td align="left">同上</td>
<td align="left">更新 resource_type</td>
<td align="left">不存在时将更新失败</td>
</tr>
<tr>
<td align="left">delete_resource_type</td>
<td align="left"><code>{"id": "theid"}</code></td>
<td align="left">删除 resource_type</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">upsert_instance_selection</td>
<td align="left">Map, <a href="../../Reference/API/02-Model/12-InstanceSelection.md">格式</a></td>
<td align="left">新增或更新 instance_selection</td>
<td align="left"><strong>推荐</strong></td>
</tr>
<tr>
<td align="left">add_instance_selection</td>
<td align="left">同上</td>
<td align="left">新增 instance_selection</td>
<td align="left">当 instance_selection 已存在时将新增失败</td>
</tr>
<tr>
<td align="left">update_instance_selection</td>
<td align="left">同上</td>
<td align="left">更新 instance_selection</td>
<td align="left">不存在时将更新失败</td>
</tr>
<tr>
<td align="left">delete_instance_selection</td>
<td align="left"><code>{"id": "theid"}</code></td>
<td align="left">删除 instance_selection</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">upsert_action</td>
<td align="left">Map, <a href="../../Reference/API/02-Model/13-Action.md">格式</a></td>
<td align="left">新增或更新 action</td>
<td align="left"><strong>推荐</strong></td>
</tr>
<tr>
<td align="left">add_action</td>
<td align="left">同上</td>
<td align="left">新增 action</td>
<td align="left">当 action 已存在时将新增失败</td>
</tr>
<tr>
<td align="left">update_action</td>
<td align="left">同上</td>
<td align="left">更新 action</td>
<td align="left">不存在时将更新失败</td>
</tr>
<tr>
<td align="left">delete_action</td>
<td align="left"><code>{"id": "theid"}</code></td>
<td align="left">删除 action</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">upsert_action_groups</td>
<td align="left"><code>array[map]</code> <a href="../../Reference/API/02-Model/14-ActionGroup.md">格式</a></td>
<td align="left">新增或更新操作组</td>
<td align="left"><strong>推荐</strong></td>
</tr>
<tr>
<td align="left">upsert_resource_creator_actions</td>
<td align="left"><code>Map</code>, <a href="../../Reference/API/02-Model/19-ResourceCreatorAction.md">格式</a></td>
<td align="left">新增或更新新建关联配置</td>
<td align="left"><strong>推荐</strong></td>
</tr>
<tr>
<td align="left">upsert_common_actions</td>
<td align="left"><code>array[map]</code>, <a href="../../Reference/API/02-Model/17-CommonActions.md">格式</a></td>
<td align="left">新增或更新常用操作配置</td>
<td align="left"><strong>推荐</strong></td>
</tr>
<tr>
<td align="left">upsert_feature_shield_rules</td>
<td align="left"><code>array[map]</code>, <a href="../../Reference/API/02-Model/18-FeatureShieldRules.md">格式</a></td>
<td align="left">新增或更新功能开关配置</td>
<td align="left"><strong>推荐</strong></td>
</tr>
</tbody>
</table>
<p><strong>建议:</strong>: 如果 migration 中存在多个操作, <code>新增</code>建议使用<code>upsert</code>来实现, 而不是<code>add_</code>来实现, <code>add_</code>将会导致, 同一个 migration 只能执行一次; 重复执行会报错(资源已存在)</p>
<p><strong>重要</strong>: 注册 system 和更新 system 的时候, 其 client 务必包含自己的<code>app_code</code>; 否则一旦注册或更新成功, 这个系统的 clients 中不包含自己的 app_code, 此时无权限进行后续的所有操作!!!!</p><h1 id="_1">依赖操作权限方案</h1>
<h2 id="_2">背景</h2>
<p>用户在申请操作 A 权限时，操作 A 依赖于操作 B，IAM 在创建申请单时会同时帮用户申请操作 B 的权限</p>
<p>比如: 用户申请 编辑主机 权限的前提是用户需要有 查看主机 权限，那么 查看主机 就是 编辑主机 的依赖权限，用户在申请 编辑主机 时，IAM 会同时帮用户申请 查看主机 的权限</p>
<h2 id="_3">接入系统注册操作的依赖操作</h2>
<p>详细见<a href="../../Reference/API/02-Model/13-Action.md">注册操作 API</a>的<code>related_actions</code>字段</p>
<h2 id="_4">依赖操作产生权限的规则</h2>
<ul>
<li>申请操作: 用户在权限中心申请后勾选操作</li>
<li>依赖操作: 接入系统注册操作时填写的<code>related_actions</code></li>
</ul>
<p>限制:</p>
<ul>
<li>用户申请操作权限中包含属性(实例+属性或单属性)的条件时不会产生依赖操作权限</li>
<li>产生依赖操作的同时，不会产生依赖操作的依赖操作权限，即只会有一层依赖操作产生，不会递归创建依赖操作权限</li>
<li>依赖操作不能关联多个资源类型</li>
</ul>
<p>规则:</p>
<h3 id="1">1. 申请操作与依赖操作关联资源类型相同</h3>
<p>例 1:</p>
<ul>
<li>申请操作: edit_host 关联的资源类型 host</li>
<li>
<p>依赖操作: view_host 关联的资源类型 host</p>
<ul>
<li>view_host 的 host 有 biz-set-module-host 实例视图</li>
</ul>
</li>
<li>
<p>用户申请了 edit_host 的拓扑权限 /biz,1/set,2，该拓扑满足 view_host 的实例视图的前缀匹配，会产生/biz,1/set,2 的 view_host 权限</p>
</li>
<li>用户申请了 edit_host 的实例权限 /biz,2/host,1，由于 view_host 没有 biz-host 前缀的实例视图，不会产生 view_host 的依赖权限</li>
<li>用户申请了 edit_host 的任意权限，产生 view_host 的任意权限</li>
</ul>
<h3 id="2">2. 依赖操作不关联资源类型</h3>
<p>例 1:</p>
<ul>
<li>申请操作: edit_job 关联的资源类型 job</li>
<li>依赖操作: create_job 不关联资源类型</li>
</ul>
<p>用户申请了 edit_job 的权限，无论是什么权限，都会产生 create_job 权限</p>
<h3 id="3">3. 申请操作与依赖操作关联的资源类型不同</h3>
<p>例 1:</p>
<ul>
<li>申请操作: edit_host 关联的资源类型 host</li>
<li>
<p>依赖操作: view_biz 关联资源类型 biz</p>
<ul>
<li>view_biz 的 biz 有 biz 实例视图</li>
</ul>
</li>
<li>
<p>用户申请了 edit_host 的拓扑权限 /biz,1/set,2，该拓扑满足 view_biz 的实例视图的前缀匹配，会产生/biz,1 的 view_biz 权限</p>
</li>
<li>用户申请了 edit_host 的拓扑权限 /set,1/host,2，该拓扑不满足满足 view_biz 的实例视图的前缀匹配，不会产生 view_biz 权限</li>
<li>用户申请了 edit_host 的任意权限，不会产生 view_biz 的权限</li>
</ul>
<h3 id="4">4. 申请操作不关联资源类型</h3>
<p>例 1:</p>
<ul>
<li>申请操作: create_host 未关联资源类型</li>
<li>
<p>依赖操作: view_biz 关联资源类型 biz</p>
<ul>
<li>view_biz 的 biz 有 biz 实例视图</li>
</ul>
</li>
<li>
<p>用户申请了 create_host 的权限，不会创建 view_biz 权限</p>
</li>
</ul>
<p>例 2:</p>
<ul>
<li>申请操作: create_host 未关联资源类型</li>
<li>
<p>依赖操作: create_biz 未关联资源类型</p>
</li>
<li>
<p>用户申请了 create_host 的权限，产生 view_biz 权限</p>
</li>
</ul>
<h3 id="5">5. 申请操作关联多个资源类型</h3>
<p>例 1:</p>
<ul>
<li>申请操作: execute_job 关联资源类型 job host</li>
<li>
<p>依赖操作: view_job 关联资源类型 job</p>
<ul>
<li>view_job 的 job 有 biz-job 的实例视图</li>
</ul>
</li>
<li>
<p>用户申请 execute_job 的权限其中 job 的拓扑满足 view_job 的 job 的实例视图前缀，产生对应的 view_job 权限</p>
</li>
<li>用户申请 execute_job 的权限其中 job 是任意，产生 view_job 的任意权限</li>
</ul>
<p>例 2:</p>
<ul>
<li>申请操作: execute_job 关联资源类型 job host</li>
<li>
<p>依赖操作: view_biz 关联资源类型 biz</p>
<ul>
<li>view_biz 的 biz 有 biz 的实例视图</li>
</ul>
</li>
<li>
<p>用户申请 execute_job 的权限其中 job 与 host 的拓扑同时满足 view_biz 的 biz 的实例视图前缀，产生对应的 view_biz 权限</p>
</li>
<li>用户申请 execute_job 的权限是任意，不产生 view_biz 权限</li>
</ul><h1 id="_1">新建关联权限方案</h1>
<h2 id="_2">一、背景&amp;需求</h2>
<p>一个新的资源实例产生时，需要其创建者有该实例的某些操作权限</p>
<p>比如一个作业创建时，创建者需要有该作业的编辑、删除和查看权限</p>
<h2 id="_3">二、实现方案</h2>
<ol>
<li><code>接入系统</code> 注册每种资源产生时对应创建者应该赋予的操作列表，且这数据将作为接入系统规定的创建者默认的权限</li>
<li><code>接入系统</code> 在产生新的资源实例时，必须调用<code>权限中心</code>API 知会权限中心新实例的产生并带其创建者</li>
</ol>
<h3 id="1">1. 接入系统 注册的新建关联配置数据结构</h3>
<blockquote>
<p>层级结构是依据资源的层级，后续权限中心将会支持这份配置可由企业全局修改和每个用户自定义</p>
</blockquote>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">config</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">新建关联的配置文件，包含了每种资源类型对应的创建时可以对创建者进行授权的 Action</td>
</tr>
</tbody>
</table>
<p>config 里的每个元素的字段说明:</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型的唯一标识</td>
</tr>
<tr>
<td align="left">actions</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">对应资源被创建时可以对创建者进行授权的 Action 列表</td>
</tr>
<tr>
<td align="left">sub_resource_types</td>
<td align="left">array(object)</td>
<td align="left">否</td>
<td align="left">子资源类型相关可授权的 Action 相关配置信息，列表每个元素同 config 列表里的每个元素一样，这是个递归结构</td>
</tr>
</tbody>
</table>
<p>actions 里的每个元素的字段说明：</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">Action 的唯一标识</td>
</tr>
<tr>
<td align="left">required</td>
<td align="left">bool</td>
<td align="left">是</td>
<td align="left">该 Action 是否是必须的，即后续权限中心支持企业和用户修改创建者赋权时，该 Action 能否不被选择授予</td>
</tr>
</tbody>
</table>
<p><strong>required 字段特别说明</strong></p>
<p>假设资源类型 host 产生时可以对 host_edit 、host_view、host_delete 这 3 个权限授权，且 host_delete 配置 required=true</p>
<ul>
<li>后续权限中心将支持用户和企业自定义这个新建关联的配置时，host_delete 是必选的，无法去除</li>
<li>如果用户自定义新建管理的配置是 host 产生时对 host_view、host_delete 这 2 个权限授权（host_edit 和 host_view 由于 required=false，所以是可以配置为不授权的），那么该用户在接入系统新增 host 后，自动拥有 host_view 和 host_delete</li>
</ul>
<h4 id="cmdb">[样例参考] cmdb 新建关联配置</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;config&quot;:[
        {
            &quot;id&quot;:&quot;biz&quot;,
            &quot;actions&quot;:[
                {
                    &quot;id&quot;:&quot;biz_edit&quot;,
                    &quot;required&quot;:false
                },
                {
                    &quot;id&quot;:&quot;biz_view&quot;,
                    &quot;required&quot;:true
                },
                {
                    &quot;id&quot;:&quot;set_create&quot;,
                    &quot;required&quot;:false
                }
            ],
            &quot;sub_resource_types&quot;:[
                {
                    &quot;id&quot;:&quot;set&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;set_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;set_view&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;module_create&quot;,
                            &quot;required&quot;:false
                        }
                    ],
                    &quot;sub_resource_types&quot;:[
                        {
                            &quot;id&quot;:&quot;module&quot;,
                            &quot;actions&quot;:[
                                {
                                    &quot;id&quot;:&quot;module_edit&quot;,
                                    &quot;required&quot;:false
                                },
                                {
                                    &quot;id&quot;:&quot;module_view&quot;,
                                    &quot;required&quot;:false
                                },
                                {
                                    &quot;id&quot;:&quot;host_create&quot;,
                                    &quot;required&quot;:false
                                }
                            ],
                            &quot;sub_resource_types&quot;:[
                                {
                                    &quot;id&quot;:&quot;host&quot;,
                                    &quot;actions&quot;:[
                                        {
                                            &quot;id&quot;:&quot;host_edit&quot;,
                                            &quot;required&quot;:false
                                        },
                                        {
                                            &quot;id&quot;:&quot;host_view&quot;,
                                            &quot;required&quot;:false
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}</code></pre>


<p>说明：
- 用户新增 biz1 时，则用户将会对 biz1 有 biz_edit、biz_view 以及在 biz1 下 set_create 的权限
- 用户新增 set1 时，则用户将会对 set1 有 set_edit、set_view 以及在 set1 下 module_create 的权限</p>
<h4 id="_4">[样例参考] 标准运维新建关联配置</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;config&quot;:[
        {
            &quot;id&quot;:&quot;project&quot;,
            &quot;actions&quot;:[
                {
                    &quot;id&quot;:&quot;project_fast_create_task&quot;,
                    &quot;required&quot;:false
                },
                {
                    &quot;id&quot;:&quot;flow_create&quot;,
                    &quot;required&quot;:false
                },
                {
                    &quot;id&quot;:&quot;project_edit&quot;,
                    &quot;required&quot;:false
                },
                {
                    &quot;id&quot;:&quot;project_view&quot;,
                    &quot;required&quot;:false
                }
            ],
            &quot;sub_resource_types&quot;:[
                {
                    &quot;id&quot;:&quot;common_flow&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;common_flow_view&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;common_flow_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;common_flow_delete&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                },
                {
                    &quot;id&quot;:&quot;flow&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;flow_create_periodic_task&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_create_mini_app&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_create_task&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_delete&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_view&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                },
                {
                    &quot;id&quot;:&quot;mini_app&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;mini_app_create_task&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;mini_app_delete&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;mini_app_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;mini_app_view&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                },
                {
                    &quot;id&quot;:&quot;periodic_task&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;periodic_task_view&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;periodic_task_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;periodic_task_delete&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                },
                {
                    &quot;id&quot;:&quot;task&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;task_view&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_operate&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_claim&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_delete&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_clone&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                }
            ]
        }
    ]
}</code></pre>


<h3 id="2">2. 接入系统在资源新增时，调用权限中心接口</h3>
<p>接口需要的数据信息如下：</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型的唯一标识</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的唯一标识</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的名称</td>
</tr>
<tr>
<td align="left">creator</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的创建者</td>
</tr>
<tr>
<td align="left">ancestors</td>
<td align="left">array(object)</td>
<td align="left">否</td>
<td align="left">资源的祖先，非必填，对于资源实例可能存在不同拓扑层级且某些操作需要按照拓扑层级鉴权时，该字段则需要填写，详细说明请看 ancestors 特别说明</td>
</tr>
</tbody>
</table>
<p>ancestors 列表的元素说明</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">祖先资源类型的唯一标识</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">祖先资源实例的唯一标识</td>
</tr>
</tbody>
</table>
<p><strong>ancestors 特别说明</strong></p>
<p>假设接入系统存在资源实例可以属于不同拓扑层级，比如：主机 A 可以在蓝鲸业务的 Web 模块，也可以在蓝鲸业务的 DB 模块下，同时需要限制用户 X 只能在 Web 模块下修改主机相关属性，而不能在 DB 模块下修改主机属性</p>
<p>那么对于修改主机属性这个操作，其鉴权是需要区分拓扑祖先层级的，即 用户 X 能编辑 /biz,bk/module,web/host,A/ 主机属性，所以授权时不能直接授予用户 X 能编辑 host,A 主机属性，否则用户 X 将在 DB 模块和 Web 模块下都可以编辑主机 host,A</p>
<p>对于存在以上的情况的，在资源实例产生时需要给到 ancestors，这样权限中心将会按照拓扑层级来授权，否则将直接授权资源实例(不带拓扑层级)</p>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;:&quot;xxxxx&quot;,
    &quot;id&quot;:&quot;xxx&quot;,
    &quot;name&quot;:&quot;xxxx&quot;,
    &quot;creator&quot;:&quot;jianan&quot;,
    &quot;ancestors&quot;:[
        {
            &quot;type&quot;:&quot;xxxxxx&quot;,
            &quot;id&quot;:&quot;yyy&quot;
        }
    ]
}</code></pre><h1 id="_1">有权限的资源列表</h1>
<h2 id="_2">背景</h2>
<p>系统接入权限中心后, 用户相关的权限都在权限中心统一维护. </p>
<p>系统产品上, 用户登录后, 需要展示有权限的资源列表, 例如<code>用户1有主机编辑权限的所有主机列表</code></p>
<p>此时, 所有的<code>主机资源</code>是接入系统自己维护的, 而<code>用户 1 的主机编辑权限</code>是权限中心维护的.</p>
<p>由于权限中心没有持有<code>资源</code>, 所以获取有权限的资源列表需要接入系统查询获取策略后进行处理</p>
<h2 id="1">方案 1: 表达式解析</h2>
<blockquote>
<p>推荐做法</p>
</blockquote>
<p>将权限中心的条件表达式, 转换成系统自己存储的查询语句, 例如 sql, django queryset, mongodb query 或者 elasticsearch Query DSL. </p>
<p>在 <a href="https://github.com/TencentBlueKing/iam-python-sdk/tree/master/iam/contrib/converter">Python SDK</a> 中, 我们给到了两种实现, 具体见文档: <a href="../../Reference/Expression/03-Translate.md">表达式解析</a></p>
<p>如果系统实现了相关存储的表达式解析, 欢迎贡献 PR 到对应的 SDK 仓库.</p>
<h2 id="2">方案 2: 批量鉴权</h2>
<blockquote>
<p>小规模资源</p>
</blockquote>
<p>使用 SDK 进行鉴权的逻辑是, 查询<code>用户 1 编辑主机</code>的权限策略到本地, 然后将资源带入进行计算, 而计算是在内存中进行的, 效率非常高.</p>
<p>批量 1000 台主机鉴权, 也是一次策略查询, 然后将 1000 台主机循环带入计算.</p>
<p>具体实现可以参考各个 SDK 提供的批量鉴权接口 <a href="../../Reference/SDK/01-PythonSDK.md">Python SDK</a> / <a href="../../Reference/SDK/02-GoSDK.md">Go SDK</a> / <a href="../../Reference/SDK/03-JavaSDK.md">Java SDK</a> / <a href="../../Reference/SDK/05-PHPSDK.md">PHP SDK</a></p>
<p>所以, 如果接入资源的规模可控, 可以使用批量鉴权的方式实现.</p>
<h2 id="3">方案 3: 自行转换</h2>
<p>接入系统的资源存储可能非常复杂, 多个表, 甚至是依赖外部的服务拉取.</p>
<p>此时, 前两个方案可能解决不了问题, 此时, 需要系统自行将策略表达式转换成等价的<code>查询+过滤</code>.</p>
<p>注意: 这类场景权限中心是无法处理的, 需要接入系统理解权限中心的策略表达式, 并做等价的转换. </p>
<p>建议接入系统权限模型尽量简单, 资源尽量是<code>实体</code>资源(例如对应 db 一个表), 而不是<code>抽象</code>资源.</p><h1 id="_1">有资源权限的用户列表</h1>
<h2 id="_2">背景</h2>
<p>系统接入权限中心后, 用户相关的权限都在权限中心统一维护. </p>
<p>系统产品上, 用户登录后, 需要展示有资源权限的用户列表, 例如<code>有主机 1编辑权限的用户列表</code>.</p>
<h2 id="_3">困难</h2>
<p>此时, 由于权限的来源非常复杂:
- 来自于个人实例权限<code>用户 1 - 主机 1</code>
- 来自于拓扑 <code>用户 2 - 业务 A 下的所有主机权限</code>, <code>主机 1 属于业务 A</code>
- 来自于属性 <code>用户 3 - 所有system=linux的主机权限</code>, <code>主机 1 的system=linux</code>
- 继承于部门 <code>部门 1 - 主机 1</code>, <code>用户 4 属于部门 1</code>
- 继承于组 <code>组 1 - 主机 1</code>, <code>用户 5 属于组 1</code></p>
<p>并且, 由于权限本身是一个动态的表达式, 当 1000 个人配置策略, 会有 1000 条表达式, 需要从里面判断是否有<code>主机 1 编辑权限</code>的时候, 需要全部计算.</p>
<p>所以, 当前阶段是无法获取有某个资源权限的用户列表的.</p>
<h2 id="1">解决方案 1</h2>
<p>我们实现了一个基于检索引擎加实时计算的服务<code>iam-search-engine</code></p>
<p>这个引擎会定期同步全量的策略数据, 进行分析, 之后索引.</p>
<p>基于这个服务, 我们可以使用<code>操作+具体资源</code>, 检索有资源权限的用户列表/组列表; </p>
<p>注意, 如果个人权限继承自于部门或者组, 这个服务只能返回组, 不能展示组下部门/部门下成员等, 需要接入系统调用接口进一步查看;</p>
<p>注意, 这个服务只能查询 Top 100 的用户列表, 无法支持全量或分页(因为结果来自于多个引擎, 除了全文检索, 还有实时计算)</p>
<p>注意, 这个服务还在灰度测试中, 测试完成后进行出包并开源.</p>
<h2 id="2">解决方案 2: 操作的用户列表</h2>
<p>某些审计需求, 接入系统需要知道某个操作的有权限的 subject 列表. 或者只是为了一个计数.</p>
<p>此时, 可以通过 <a href="../../Reference/API/08-Query/02-PolicyList.md">policy list 查询接口</a></p>
<p>此时, 可以查询到一个操作的所有策略表达式及对应的<code>subject</code>;</p>
<p>注意, <code>subject</code>会重复, 需要接入系统自行去重/统计; </p><h1 id="id">最佳实践: 资源 ID</h1>
<h2 id="id_1">资源 ID</h2>
<p>Resource ID 是接入系统维护, 唯一标识一个资源; </p>
<p>这个 ID 用于配置权限, 会存储在策略表达式中; </p>
<h2 id="_1">类型</h2>
<p>目前, 大部分系统的资源 ID 是: <code>数据库自增主键</code>, 例如, 长度为 6 位的 ID, 可以表示最多<code>999999</code>个资源</p>
<p>而部分系统, 其资源 ID 存在为 <code>MD5/Hash</code> 字符串等, 此时 ID 长度会是 <code>32/36/64</code> 等, 甚至更长</p>
<h2 id="_2">策略大小</h2>
<p>长度为 6/32 的 ID 策略大小:</p>
<table>
<thead>
<tr>
<th>ID 数量</th>
<th>长度 6 策略大小(KB)</th>
<th>长度 32 策略大小(KB)</th>
</tr>
</thead>
<tbody>
<tr>
<td>100</td>
<td>1.14</td>
<td>3.5</td>
</tr>
<tr>
<td>1000</td>
<td>9.06</td>
<td>32.5</td>
</tr>
<tr>
<td>10000</td>
<td>88</td>
<td>322</td>
</tr>
<tr>
<td>20000</td>
<td>175</td>
<td>645</td>
</tr>
<tr>
<td>50000</td>
<td>439</td>
<td>1611</td>
</tr>
</tbody>
</table>
<h2 id="_3">影响</h2>
<p>ID 的数量以及 ID 本身的长度, 会影响到整体鉴权的性能(策略大小, 网络传输, 内存计算)</p>
<p>而这个性能是无法进行优化的, 是因为 ID 长度导致的开销.</p>
<h2 id="_4">最佳实践</h2>
<p>建议尽量使用<code>数据库自增主键</code>这类整数 ID, 避免使用 <code>MD5/Hash</code> 等 ID</p><h1 id="_1">问题排查指引</h1>
<p>如果有<code>错误码</code>, 优先看错误码</p>
<ul>
<li><a href="ErrorCode.md">错误码</a></li>
</ul>
<p>如果是下面这几类问题, 直接跳转到对应文档</p>
<ul>
<li><a href="Debug/SaaS-Callback.md">常见: SaaS 回调接入系统失败</a></li>
<li><a href="Debug/SaaS-DeptSync.md">常见: SaaS 组织架构同步异常</a></li>
<li><a href="Debug/PolicyAPIDebug.md">常见: 为什么有权限/无权限</a></li>
</ul>
<hr />
<h2 id="1">1. 开发接入</h2>
<p>当遇到调用权限中心接口报错, 首先</p>
<ol>
<li>确认请求响应的 <a href="ErrorCode.md">错误码</a> 确认问题, 并根据指引解决</li>
<li>查找 FAQ</li>
<li>如果无法自助解决, 需要提单由权限中心开发协助排查, 请 <a href="Debug/Issue.md">提单模板</a> 提供环境/请求/响应等信息. 请务必按照要求填写, 便于更快速定位解决问题</li>
</ol>
<h2 id="2-saas">2. 使用权限中心 SaaS 过程中发现<code>未知错误</code></h2>
<p>客户在发现 SaaS 使用过程中出现 <code>未知错误</code> , 可以通过 <code>request_id</code> 查询到相关的调试信息, 提单时附加到单据中; </p>
<ul>
<li>如果配置权限回调接入系统报错, 根据 <a href="Debug/SaaS-Callback.md">回调接入系统失败</a></li>
<li>如果是组织架构同步异常/失败, 根据 <a href="Debug/SaaS-DeptSync.md">组织架构同步异常</a> 自助排查</li>
<li>可以根据 <a href="Debug/SelfHelp/SaaS-DebugTraceAPI.md">自助排查: SaaS 报错 Debug</a> 自助通过<code>request_id</code>获取报错详情;</li>
</ul>
<h2 id="3">3. 对权限有疑问</h2>
<p>鉴权接口正常返回, 但是不符合预期(为什么有权限/为什么无权限)</p>
<ol>
<li>到权限中心 SaaS 页面, 查看个人权限, 确认个人权限 / 组织架构权限 / 组权限 (大概率是继承了上级部门或所属组的权限)</li>
<li>想进一步从请求中确认权限计算细节; 可以根据 SDK 文档, 开启 debug 模式; 或者阅读 <a href="Debug/PolicyAPIDebug.md">鉴权接口 debug</a> 文档, 通过在请求参数中加<code>?debug=true</code>, 开启接口<code>debug</code>, 可以看到详细的策略计算流程; 如果怀疑是缓存问题, 可以加上<code>?force=true</code>参数, 强制走实时数据查询, 不走缓存;</li>
</ol>
<h2 id="4">4. 运维问题</h2>
<ol>
<li><a href="../OPS/Debug.md">确认权限中心服务是否可用？</a> </li>
</ol>
<h2 id="5">5. 进阶</h2>
<p>权限中心提供了 debug-cli, 用于深入定位一些复杂问题</p>
<p>用户可以</p>
<ol>
<li>根据文档指引中的问题排查步骤, 使用 debug-cli 获取信息</li>
<li>同权限中心开发协作, 共同排查生产问题</li>
<li>自行阅读文档, 自助排查问题</li>
</ol>
<p><a href="Debug/SelfHelp/DebugCLI.md">自助排查: IAM-Debug CLI</a> 使用文档</p><h1 id="_1">错误码</h1>
<h2 id="_2">错误码总览</h2>
<table>
<thead>
<tr>
<th align="left">错误码</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">1901002</td>
<td align="left">参数错误</td>
</tr>
<tr>
<td align="left">1901400</td>
<td align="left">用户传入的参数非法 (bad request)</td>
</tr>
<tr>
<td align="left">1901401</td>
<td align="left">没有权限调用接口 (unauthorized)</td>
</tr>
<tr>
<td align="left">1901403</td>
<td align="left">无访问权限</td>
</tr>
<tr>
<td align="left">1901404</td>
<td align="left">资源不存在 (not found)</td>
</tr>
<tr>
<td align="left">1901409</td>
<td align="left">资源冲突 (conflict)</td>
</tr>
<tr>
<td align="left">1901500</td>
<td align="left">500 系统错误 (system error)</td>
</tr>
<tr>
<td align="left">1902000</td>
<td align="left">依赖系统 api 不可达</td>
</tr>
<tr>
<td align="left">1902001</td>
<td align="left">ESB api 调用错误</td>
</tr>
<tr>
<td align="left">1902101</td>
<td align="left">IAM 后台请求返回码非 0</td>
</tr>
<tr>
<td align="left">1902102</td>
<td align="left">请求 ENGINE 错误</td>
</tr>
<tr>
<td align="left">1902301</td>
<td align="left">用户管理 api 调用错误</td>
</tr>
<tr>
<td align="left">1902400</td>
<td align="left">请求通用错误</td>
</tr>
<tr>
<td align="left">1902409</td>
<td align="left">请求数据与已存在数据有冲突</td>
</tr>
<tr>
<td align="left">1902412</td>
<td align="left">请求参数校验错误</td>
</tr>
<tr>
<td align="left">1902413</td>
<td align="left">请求第三方接口失败</td>
</tr>
<tr>
<td align="left">1902414</td>
<td align="left">请求参数 JSON 格式错误</td>
</tr>
<tr>
<td align="left">1902415</td>
<td align="left">请求方法不支持</td>
</tr>
<tr>
<td align="left">1902416</td>
<td align="left">请求参数错误</td>
</tr>
<tr>
<td align="left">1902417</td>
<td align="left">操作数据检查错误</td>
</tr>
<tr>
<td align="left">1902418</td>
<td align="left">用户组转出错误</td>
</tr>
<tr>
<td align="left">1902419</td>
<td align="left">请求数值错误</td>
</tr>
<tr>
<td align="left">1902401</td>
<td align="left">用户未登录</td>
</tr>
<tr>
<td align="left">1902403</td>
<td align="left">用户无权限访问</td>
</tr>
<tr>
<td align="left">1902404</td>
<td align="left">数据不存在</td>
</tr>
<tr>
<td align="left">1902200</td>
<td align="left">接入系统资源接口请求失败</td>
</tr>
<tr>
<td align="left">1902201</td>
<td align="left">接入系统资源接口请求 API 认证失败</td>
</tr>
<tr>
<td align="left">1902204</td>
<td align="left">接入系统不存在请求的资源类型或未实现该资源的查询方法</td>
</tr>
<tr>
<td align="left">1902206</td>
<td align="left">搜索 Keyword 参数校验失败</td>
</tr>
<tr>
<td align="left">1902222</td>
<td align="left">接入系统需返回的资源内容过多，拒绝返回数据</td>
</tr>
<tr>
<td align="left">1902229</td>
<td align="left">请求频率超出接入系统 API 频率限制</td>
</tr>
<tr>
<td align="left">1902250</td>
<td align="left">接入系统自身接口异常</td>
</tr>
<tr>
<td align="left">1902250</td>
<td align="left">接入系统自身接口返回数据不符合要求</td>
</tr>
<tr>
<td align="left">1902501</td>
<td align="left">ITSM 请求返回码非 0</td>
</tr>
<tr>
<td align="left">1902502</td>
<td align="left">ITSM 流程里存在 IAM 不支持的流程处理者</td>
</tr>
</tbody>
</table>
<h2 id="_3">后台错误码</h2>
<p>注意, 如果想确认目前环境中注册的权限模型, </p>
<p>可以用接口 <a href="../../Reference/API/02-Model/15-CommonQuery.md">权限模型: 通用查询 Common Query API</a> 查询.</p>
<h3 id="1901400">1901400</h3>
<blockquote>
<p>bad request: {message}</p>
</blockquote>
<p>用户传入的参数非法, 不符合规范. 详细信息在 message 中</p>
<p>需要仔细接口协议, 确保调用的 URL/参数等符合要求</p>
<p>举例: <code>bad request:json decode or validate fail, err=[0]: Key: 'commonActionSerializer.Actions' Error:Field validation for 'Actions' failed on the 'gt' tag</code> 常用操作<code>actions</code>必须至少一个 (使用了开源validation库的validate规则, 提示信息可能没那么清晰)</p>
<blockquote>
<p>bad request:action.id invalid</p>
</blockquote>
<p><code>action.id</code>非法, 确认下这个环境注册的权限模型中是否有这个操作</p>
<p>可以使用<a href="../../Reference/API/02-Model/15-CommonQuery.md">权限模型: 通用查询 Common Query API</a> 查询确认</p>
<blockquote>
<p>bad request:get system(xxxx) valid clients fail, err=[Cache:GetSystemClients] LocalSystemClientsCache.Get key=<code>xxx</code> fail =&gt; [SystemSVC:Get] saasManager.Get id=<code>xxx</code> fail =&gt; [Raw:Error] sql: no rows in result set</p>
</blockquote>
<p>找不到这个注册的系统</p>
<p>确认系统是否注册</p>
<h3 id="1901401">1901401</h3>
<blockquote>
<p>unauthorized: app code and app secret required</p>
</blockquote>
<p>请求 header 中没有传递 <code>X-Bk-App-Code/X-Bk-App-Secret</code></p>
<blockquote>
<p>unauthorized: app code or app secret wrong</p>
</blockquote>
<p>请求 header 中传递的 <code>X-Bk-App-Code/X-Bk-App-Secret</code> 错误, 无法在该环境找到匹配的.</p>
<p>需要确认:
- 是否传递了 <code>X-Bk-App-Code/X-Bk-App-Secret</code> 且非空
- 对应的 <code>app_code</code> 和 <code>app_secret</code> 是在同一个环境生成的
- 再次确认 <code>app_code/app_secret</code> 是否同应用详情页信息匹配(经常出现的是复制错/复制漏)`
- 由于认证存在缓存，第一次错误后，相同 AppCode 和 AppSecret 必须等待 5 秒以上才能再请求
- 如果无法确认, 请提供请求详情.</p>
<blockquote>
<p>unauthorized: app(xxx) is not allowed to call system (yyy) api" </p>
</blockquote>
<p>xxx 这个 app_code 不允许调用系统 yyy 的资源, 需要将 xxx 加入到 yyy 的 clients`中. 具体见  <a href="../../Reference/API/02-Model/10-System.md">系统(System) API</a></p>
<h3 id="1901404">1901404</h3>
<blockquote>
<p>not found: system(xxx) not exists </p>
</blockquote>
<p>系统 xxx 不存在, 请确认系统已注册(注意, system 是接入系统注册到权限中心的, <code>clients</code>中配置的是可以调用这个系统 API 的合法<code>app_code</code>, 不要混淆二者概念)</p>
<h3 id="1901409">1901409</h3>
<blockquote>
<p>conflict:instance selection name[xxxx] already exists</p>
</blockquote>
<p>资源冲突, 接口创建的<code>xxxx</code>已存在.</p>
<p>可以使用<a href="../../Reference/API/02-Model/15-CommonQuery.md">权限模型: 通用查询 Common Query API</a> 查询确认</p>
<blockquote>
<p>conflict:action has releated policies, you can't delete it or update the related_resource_types unless delete all the related policies. please contact administrator.</p>
</blockquote>
<p>操作已经被使用配置了相关的权限, 不能删除 action 或者改变这个 action 的 related_resource_types. 联系管理员, 通过权限中心 SaaS 的 Django Command 进行<code>权限升级</code>或者<code>权限清理</code>;</p>
<h3 id="1901500">1901500</h3>
<blockquote>
<p>[SubjectSVC:GetPK] GetPK _type=user, id=xxx fail =&gt; [Raw:Error] sql: no rows in result set</p>
</blockquote>
<p>原因: 用户在权限中心不存在, 新增用户未同步到权限中心, 或者用户被删除.</p>
<p>处理: 在用户管理新增用户后, 需要到权限中心做一次同步(同步所有组织架构需要 10 分钟左右)</p>
<p>默认权限中心从用户管理一天同步一次组织架构.</p>
<blockquote>
<p>request resources not match action =\u003e [Raw:Error] validateActionResource fail</p>
</blockquote>
<p>用户请求查询时传入的资源(resources) 同接入系统注册操作的关联资源类型(related_resource_types)不匹配</p>
<p>例如注册查看主机关联的资源类型是<code>主机</code>, 但是查询策略的时候传入的<code>action=查看主机, resources=[集群]</code> 此时校验操作的资源类型失败</p>
<p>确认是否是以下场景:</p>
<ul>
<li>操作关联了两个资源类型, 鉴权只传一个</li>
<li>操作关联资源类型 A, 鉴权时传递资源类型 B</li>
</ul>
<blockquote>
<p>[Cache:GetActionPK] ActionPKCache.Get key={system_x}:{action_y} fail =&gt; [Raw:Error] sql: no rows in result set</p>
</blockquote>
<p>用户请求传入的 action 在权限中心不存在(即 action 不在系统注册的操作列表中)</p>
<p>可能原因: 
1. 接入系统没有注册对应的<code>action</code>
2. 鉴权请求传入了错误的<code>action.id</code>
3. 接入系统变更了模型, 例如删除 action </p>
<h2 id="1902xxx-190230x">组件调用错误 1902XXX - 190230X</h2>
<p>日志查询方法:</p>
<p>找到权限中心 SaaS 的 component.log 日志, 搜索对应的请求 request_id, 查询相关 api 调用的上下文</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/ErrorCodes_1.png" /></p>
<h3 id="1902000">1902000</h3>
<p>描述: 依赖系统(esb, 权限中心后台, 用户管理) api 调用不可达</p>
<p>错误信息:</p>
<blockquote>
<p>request esb api error</p>
</blockquote>
<p>排查权限中心 SaaS 的主机是否能正常访问 ESB api</p>
<blockquote>
<p>request usermanger api error</p>
</blockquote>
<p>排查权限中心 SaaS 的主机是否能正常访问用户管理的 ESB api</p>
<blockquote>
<p>request iam api error</p>
</blockquote>
<p>排查权限中心 SaaS 的主机是否能正常访问权限中心后台 api</p>
<h3 id="1902001">1902001</h3>
<p>描述: 调用 ESB api 失败</p>
<p>提供错误信息与日志到 ESB 负责人排查</p>
<h3 id="1902200">1902200</h3>
<p>描述: 接入系统回调接口调用错误</p>
<p>错误信息:</p>
<blockquote>
<p>unreachable interface call</p>
</blockquote>
<p>接入系统接口不可达</p>
<blockquote>
<p>interface status code:<code>xxx</code>error</p>
</blockquote>
<p>接入系统接口返回状态码<code>xxx</code>错误</p>
<blockquote>
<p>Parameter error: The resource(system_id:bk_xxxx, type:page, id:244) display_name cannot be queried through the API - fetch_instance_info</p>
</blockquote>
<p>回调接口, 查询 244 资源实例时报错; 需要到被调用系统确认</p>
<p>无权限申请, 对于传入的数据，我们需要严格校验，这时候会回调 接入系统资源 fetch_instance_info接口查询资源名称</p>
<h3 id="1902201">1902201</h3>
<p><code>接入系统资源接口请求API认证失败</code>; </p>
<p>逻辑:
- 接入系统注册系统信息及回调接口, 权限中心会生成一个 token
- 权限中心回调接入系统, 会使用 basic auth, <code>username=bk_iam, password={token}</code>, 具体文档见 <a href="../../Reference/API/01-Overview/03-APIAuth.md">接口间调用鉴权</a>
- 接入系统接口, 会查询自己系统的 token,  <a href="../../Reference/API/02-Model/16-Token.md">系统 token 查询 API</a>, 进行比对
    - 如果使用的是 <code>iam-python-sdk</code>, 那么调用的是<code>IAM.get_token(system)</code>, 注意参数是<code>system</code>, 不是<code>app_code</code>
    - 如果使用了 <code>iam-python-sdk</code> 的 <code>DjangoBasicResourceApiDispatcher(iam, system)</code>, 注意参数是<code>system</code>, 不是<code>app_code</code>
- 比对失败, 返回 401, 权限中心报错误码 <code>1902201</code></p>
<p>某些场景下, 例如上云环境, app_code 和 system 是不一致的, 如果出现这个错误码, 大概率是使用<code>DjangoBasicResourceApiDispatcher</code>传递<code>system</code>参数错误</p>
<h3 id="1902250">1902250</h3>
<blockquote>
<p>接入系统自身接口异常</p>
</blockquote>
<p>调用接入系统接口失败</p>
<blockquote>
<p>接入系统自身接口返回数据进行JSON解析出错</p>
</blockquote>
<p>返回数据非json或json数据有问题</p>
<blockquote>
<p>接入系统自身接口返回数据不符合要求</p>
</blockquote>
<p>没有按协议要求返回<code>list</code>/<code>dict</code></p>
<p>出现以上问题, 需要找<strong>对应接入系统的开发人员</strong>排查解决</p>
<h3 id="1902301">1902301</h3>
<p>描述: 调用用户管理 api 失败</p>
<p>提供错误信息与日志到用户管理负责人排查</p>
<hr />
<h2 id="19024xx">用户请求错误 19024XX</h2>
<p>日志查询方法:</p>
<p>找到权限中心 SaaS 的 bk_iam-app.log 日志, 搜索对应的请求 request_id, 查询相关 api 调用的上下文</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/ErrorCodes_2.png" /></p>
<h3 id="1902403">1902403</h3>
<blockquote>
<p>app_code(bk_xxxx) do not be allowed to call api(group_list)</p>
</blockquote>
<p>需要添加白名单</p>
<blockquote>
<p>creator authorization instance api don't support the (xxxxx] of system[yyyyy]</p>
</blockquote>
<p>没有权限调用, 需要评估后, 添加白名单</p>
<blockquote>
<p>bad request:client(xxx) can not request system(yyy)</p>
</blockquote>
<p>不是该系统合法 clients</p>
<p>需要找系统权限模型的维护者, 在模型注册阶段, 将<code>app_code</code>加入到其系统合法<code>clients</code>列表中</p>
<h3 id="1902400-1902412-1902414-1902415-1902416">1902400 1902412 1902414 1902415 1902416</h3>
<p>描述: 用户的请求数据错误
说明: 请仔细阅读错误信息, 信息中包含具体原因 (如无法确定, 提供请求数据/结果返回数据/日志信息等提单到权限中心负责人排查)</p>
<blockquote>
<p>1902412 Parameter verification failed: related resource type(file_source), resource([ApplyPathNode(system_id='', type='file_source', id='53', name='')]) not satisfy instance selection"</p>
</blockquote>
<p>权限中心会校验请求中传递的资源列表, 是否与操作关联的<code>实例视图</code>链路匹配</p>
<h3 id="1902417">1902417</h3>
<p>描述: 权限提交的数据与接入系统注册操作依赖的资源类型数据校验错误</p>
<p>错误信息:</p>
<blockquote>
<p>action xxx has no related resource type yyy</p>
</blockquote>
<p>操作<code>xxx</code>不关联申请的资源类型<code>yyy</code></p>
<blockquote>
<p>action xxx related resource types yyy are in the wrong order</p>
</blockquote>
<p>操作<code>xxx</code>关联多个资源类型, 其中类型<code>yyy</code>与接入系统注册的操作关联资源类型顺序不一致</p>
<blockquote>
<p>action xxx lacks related resource type yyy</p>
</blockquote>
<p>操作<code>xxx</code>缺少资源类型<code>yyy</code></p>
<blockquote>
<p>Action check error: action <code>execute_script</code> related resource types <code>host</code> wrong</p>
</blockquote>
<p>传递的资源错误, 或者顺序与注册action的<code>releated_resource_types</code>顺序不一致</p>
<hr />
<h2 id="saas">附录: SaaS 错误码说明</h2>
<h3 id="1-api">1. 前端 api 调用错误时的提示</h3>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/ErrorCodes_3.png" /></p>
<p>当权限中心 SaaS 页面出现如上红框弹出提示时
表示
1. 回调接入系统接口失败
2. 权限中心 SaaS api 调用报错</p>
<p>点击复制, 可以获取的到报错详细信息, 根据信息分析原因</p>
<ol>
<li>如果是回调接入系统失败, 可以查看  <a href="Debug/SaaS-Callback.md">常见: SaaS 回调接入系统失败</a></li>
<li>如果是其他原因, 需要查看 api 返回的结果, 找到结果中的 code(错误码), 根据本页错误码索引确定原因</li>
</ol>
<h3 id="2-api-request_id">2. api 请求的 request_id</h3>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/ErrorCodes_4.png" /></p>
<p>权限中心 SaaS 的每个 api 请求都有 request_id, 在排查前记录 request_id, 在排查日志过程中可以更方便定位到错误信息</p>
<h3 id="3-api">3. api 返回结构说明</h3>
<pre class="codehilite"><code class="language-json">{
  &quot;code&quot;: 0,  // 返回code, 0表示成功, 其它为错误码
  &quot;data&quot;: [],
  &quot;message&quot;: &quot;OK&quot;,  // 返回的错误信息
  &quot;result&quot;: true  // 调用结果
}</code></pre><h1 id="_1">回调接入系统失败</h1>
<h2 id="1">1. 背景</h2>
<p>在权限中心配置权限, 选<code>资源实例/属性</code>时会调用对应接入系统的接口</p>
<p>如果接入系统本身服务不可用(unavailable/接口非 200), 或者网络问题等, 会导致调用失败, 页面报错提示, 用户无法配置或申请权限</p>
<p>相关<a href="../ErrorCode.md">错误码</a>: 
- 19020xx, 调用第三方请求的通用错误，比如网络不通等;
- 19022xx：回调第三方接口错误</p>
<p>接入系统回调接口本身协议及错误码: 
- <a href="../../../Reference/API/03-Callback/01-API.md">资源拉取 API 说明</a></p>
<h2 id="2">2. 产品页面表现</h2>
<p><code>接入系统资源接口请求失败</code></p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/Debug/Callback_01.jpg" /></p>
<p>内容示例:</p>
<pre class="codehilite"><code>接入系统资源接口请求失败: bk_job's API response status code is `500`, should be 200! call bk_job's API fail! you should check the network/bk_job is available and bk_job's log for more info. request: [POST /iam/api/v1/resources/task/template body.data.method=fetch_instance_info](system_id=bk_job, resource_type_id=job_template)</code></pre>


<p>注意这里 message 会包含的内容: </p>
<pre class="codehilite"><code class="language-python">request_detail_info = (
            f&quot;call {self.system_id}'s API fail! &quot;
            f&quot;you should check: &quot;
            f&quot;1.the network is ok 2.{self.system_id} is available 3.get details from {self.system_id}'s log. &quot;
            f&quot;[POST {urlparse(self.url).path} body.data.method={data['method']}]&quot;
            f&quot;(system_id={self.system_id}, resource_type_id={self.resource_type_id})&quot;
        )

error_message = f&quot;{reason}. {request_detail_info}&quot;        </code></pre>


<ul>
<li>reason: 报错原因描述</li>
<li>request_detail_info<ul>
<li>系统: system_id</li>
<li>资源类型: resource_type_id</li>
<li>http method</li>
<li>url</li>
<li>body.data.method</li>
</ul>
</li>
</ul>
<h2 id="3">3. 处理</h2>
<p><strong>重要: 从提示信息中可以获取的信息</strong>:</p>
<ul>
<li>哪个接入系统</li>
<li>哪个接口</li>
<li>参数/请求/返回/状态码/报错等详情</li>
</ul>
<p><strong>重要: 该找谁来进一步处理问题</strong>:</p>
<ul>
<li>根据报错信息, 理解问题</li>
<li>如果是环境/网络等问题, 找<strong>运维</strong>解决,</li>
<li>如果是接入系统接口问题, 根据报错信息, 到接入系统捞取对应日志, 确定问题, 找对应的<strong>开发/负责人</strong>解决(注意是对应系统的<code>开发/负责人</code>, 不是找权限中心<code>开发/负责人</code>)</li>
</ul>
<p><strong>报错的日志在哪里</strong>:</p>
<ul>
<li>权限中心 SaaS 日志 <code>component.log / bk_iam.log</code></li>
</ul>
<p><strong>注意</strong>: 一定不要单纯截一张图后提单到<code>权限中心</code>模块, 请务必获取到详细报错信息, 并且按照以上说明定位问题. 确实无法确定的再提单!</p>
<h2 id="_2">接入系统实现回调接口</h2>
<p>权限中心资源拉起时, 会根据资源拉取协议<a href="../../../Reference/API/03-Callback/01-API.md">文档</a>向接入系统发起请求, 接入系统需要返回协议规定的内容</p>
<p>当资源拉取接口失败, 此时无法配置权限; </p>
<p>所以接入系统实现相关接口时, 需要<strong>记录相关的流水日志</strong></p>
<ul>
<li>请求时间</li>
<li>请求基本信息</li>
<li>响应基本信息</li>
<li>request_id</li>
<li>如果 500, 需要记录详细报错堆栈</li>
</ul><h1 id="_1">组织架构同步异常</h1>
<h2 id="1">1. 背景</h2>
<p>权限中心支持权限授权给组织架构和用户. </p>
<p>组织架构和用户信息从用户管理同步过来:
- 每天凌晨全量同步
- 新用户自动 1 分钟内同步</p>
<p>由于用户管理接口和网络等问题导致同步组织架构失败，进而可能出现用户不存在或新用户无法同步过来等问题，所以需要根据错误码和日志进行排查解决</p>
<p>相关<a href="../ErrorCode.md">错误码</a>:
- 19023xx：通过 ESB 请求用户管理错误
- 19020xx：调用 ESB 等第三方请求的通用错误，比如网络不通等
- 19021xx：IAM 后台请求错误</p>
<h2 id="2">2. 组织架构同步依赖服务</h2>
<ol>
<li>MySQL</li>
<li>Redis，主要用于分布式锁的实现，避免同步任务并发执行</li>
<li>RabbitMQ，用于异步任务 Celery</li>
<li>IAM Backend，同步时需要变更 IAM 后台相关用户信息</li>
<li>Component - UserManager, 通过 ESB 调用用户管理提供的 API 进行组织架构同步</li>
</ol>
<h2 id="3">3. 问题排查</h2>
<p>注意, 如果需要相关开发协助排查问题, 请按下面步骤先获取报错日志再进行咨询.</p>
<h3 id="31">3.1 有超级管理员权限</h3>
<p>如果有<code>超级管理员</code>权限, 可以使用超级管理员登录后, 到权限中心首页, 直接通过页面查看同步记录/报错日志</p>
<p>路径: <code>切换角色为超级管理员 - 用户 - 组织架构</code></p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/Debug/DeptSync_00.jpg" /></p>
<p>点击<code>同步</code>按钮旁边的<code>历史记录</code>, 可以查看到历史同步的记录, 如果状态是<code>失败</code>, 点击<code>日志详情</code>可以看到详细报错日志</p>
<h3 id="32">3.2 无超级管理员权限</h3>
<p>需要结合错误码与日志排查</p>
<ol>
<li>确认 SaaS 服务健康<code>curl -vv http://{PAAS_HOST}/o/bk_iam/healthz</code>, 正常应该返回<code>ok</code> (MySQL、Redis、Celery、IAM 后台、用户管理 ESB 接口)</li>
<li>确认错误码，若有错误码，则根据错误码类型进行 <a href="../ErrorCode.md">查询</a></li>
<li>若是后台异步任务等失败，可以依次查询权限中心 SaaS 日志 <code>celery.log / component.log / bk_iam.log</code>，根据查询到的日志信息进行错误分析即可</li>
</ol>
<h2 id="4">4. 常见同步异常场景</h2>
<h3 id="41">4.1 部门查询不到</h3>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/Debug/DeptSync_01.jpg" /></p>
<ul>
<li>
<p>排查思路与步骤</p>
</li>
<li>
<p>查询出不存在的部门</p>
</li>
</ul>
<pre class="codehilite"><code class="language-bash">1). 进入IAM 容器，python shell命令行

ssh $BK_APPO_IP
docker exec -it $(docker ps | grep -w bk_iam | awk '{print $1}') bash 
/cache/.bk/env/bin/python /data/app/code/manage.py shell

2). 执行python相关语句

from backend.components import usermgr
from backend.apps.organization.models import Department
from backend.apps.organization.sync_service.utils import convert_list_for_mptt
new_departments = usermgr.list_department()
old_departments = [d for d in Department.objects.all()]
old_department_id_set = set([i.id for i in old_departments])
created_departments = [Department(id=dept[&quot;id&quot;], parent_id=dept[&quot;parent&quot;], name=dept[&quot;name&quot;], category_id=dept[&quot;category_id&quot;], order=dept[&quot;order&quot;]) for dept in new_departments if dept[&quot;id&quot;] not in old_department_id_set]
id_parent_ids = [(i.id, i.parent_id) for i in created_departments]
sorted_departments = convert_list_for_mptt(id_parent_ids)
created_department_dict = {i.id: i for i in created_departments}
data = []
for dept_id in sorted_departments:
    dept = created_department_dict[dept_id]
    data.append((dept_id, dept.parent_id))

not_exist_parent = set()
exist_dept = set()
for dept_id, dept_parent_id in data:
    exist_dept.add(dept_id)
    if dept_parent_id is None:
        continue
    if dept_parent_id not in exist_dept:
        not_exist_parent.add(dept_parent_id)

print(not_exist_parent)</code></pre>


<ol>
<li>用步骤 1 中查询到的”不存在“的部门 ID，到用户管理 DB 里查询对应部门 ID 的信息，看看是否被删除或者软删除了</li>
</ol>
<pre class="codehilite"><code class="language-bash">若在用户管理里已经删除或软删除，那说明用户管理删除后，没有一并删除其下属部门等导致的，可联系用户管理相关同事排查解决
若存在，则需要让用户管理排查是否usermgr.list_department有问题，导致没有返回对应部门</code></pre>


<h3 id="42">4.2 节点无法指定自己成为子节点的子节点</h3>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/Debug/DeptSync_02.jpg" /></p>
<ul>
<li>
<p>原因
手动修改删除用户管理数据库中部门表导致的</p>
</li>
<li>
<p>解决方式</p>
</li>
</ul>
<pre class="codehilite"><code class="language-bash">1). 进入IAM 容器，python shell命令行

ssh $BK_APPO_IP
docker exec -it $(docker ps | grep -w bk_iam | awk '{print $1}') bash 
/cache/.bk/env/bin/python /data/app/code/manage.py shell

2). 执行python相关语句
from backend.apps.organization.models import Department
Department.tree_objects.rebuild()</code></pre>


<h3 id="43">4.3 存在用户与部门关系，但是其用户不存在</h3>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/FAQ/Debug/DeptSync_03.jpg" /></p>
<ul>
<li>
<p>原因
  用户被删除了，但是其与部门之间的关系没有删除</p>
</li>
<li>
<p>解决方式</p>
</li>
</ul>
<pre class="codehilite"><code class="language-bash">1. 确认用户id=xxxx是否被删除
进入“用户管理”DB，查询profile_profiles表，查询id为xxxx的用户
用户表是软删除的，得看是否被标记为删除

2. 如果确认被删除了，则删除掉其部门</code></pre><h1 id="_1">排查: 为什么有权限/无权限</h1>
<h2 id="_2">背景</h2>
<p>接入系统在接入权限中心过程中, 可能有时候会对鉴权结果有疑问
1. 为什么这个人鉴权结果是<strong>有权限</strong>?
2. 为什么这个人鉴权结果是<strong>没有权限</strong>?</p>
<p>权限中心相应的鉴权接口, 提供了<code>api debug</code>功能</p>
<p>步骤:
1. 开启<code>api debug</code>
2. 获取对应的返回值
3. 分析确定为什么<strong>有权限/无权限</strong></p>
<h2 id="1-api-debug">1. 开启<code>api debug</code></h2>
<h3 id="11-sdk">1.1 SDK</h3>
<p>SDK 是支持通过配置或环境变量开启<code>api debug</code>的.</p>
<ul>
<li><a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/docs/usage.md#112-api-debug">iam-python-sdk debug</a></li>
<li><a href="https://github.com/TencentBlueKing/iam-go-sdk/blob/master/docs/usage.md#13-%E5%BC%80%E5%90%AFapi-debug">iam-go-sdk debug</a></li>
<li><a href="https://github.com/TencentBlueKing/iam-php-sdk/blob/master/docs/usage.md#13-%E5%BC%80%E5%90%AFapi-debug">iam-php-sdk debug</a></li>
</ul>
<h3 id="12-sdk">1.2 非 SDK</h3>
<p>直接在对应请求接口后面加入<code>?debug=true&amp;force=true</code>, 并发送请求, 获取响应结果</p>
<pre class="codehilite"><code class="language-bash">http://{IAM_HOST}/api/v1/policy/query?debug=true&amp;force=true

http://{IAM_HOST}/api/v1/policy/auth?debug=true&amp;force=true</code></pre>


<h2 id="2">2. 获取对应的返回值</h2>
<p>使用 curl 或者对应语言库, 发送<code>URL?debug=true&amp;force=true</code>请求后, 拿到的响应结果中多了一个字段<code>debug</code></p>
<pre class="codehilite"><code class="language-bash">{
    &quot;code&quot;: 0,
    &quot;data&quot;: {},
    &quot;debug&quot;: {},
    &quot;message&quot;: &quot;&quot;
}</code></pre>


<p>debug 中包含请求上下文, 获取的策略, 执行结果等详细信息</p>
<p>最终以接口返回的debug信息进行<code>是否有权限</code>排查</p>
<h2 id="3">3. 分析确定</h2>
<p>debug 信息中</p>
<p><code>expression</code>字段是最终鉴权计算的表达式</p>
<pre class="codehilite"><code class="language-json">&quot;expression&quot;: {
                &quot;content&quot;: [{
                    &quot;content&quot;: [{
                        &quot;field&quot;: &quot;host._bk_iam_path_&quot;,
                        &quot;op&quot;: &quot;starts_with&quot;,
                        &quot;value&quot;: &quot;/biz,2005000002/set,2000000004/module,2000000008/&quot;
                    }, {
                        &quot;field&quot;: &quot;host._bk_iam_path_&quot;,
                        &quot;op&quot;: &quot;starts_with&quot;,
                        &quot;value&quot;: &quot;/biz,2005000002/set,2000000005/module,*/&quot;
                    }],
                    &quot;op&quot;: &quot;OR&quot;
                }, {
                    &quot;field&quot;: &quot;biz_account.id&quot;,
                    &quot;op&quot;: &quot;any&quot;,
                    &quot;value&quot;: []
                }],
                &quot;op&quot;: &quot;AND&quot;
            }</code></pre>


<p>是一个<code>AND/OR</code>与操作符组成的逻辑表达式</p>
<p>可以将<code>debug</code>中<code>"resources"</code>字段(鉴权传递的资源)带进去, 确认下整个表达式执行结果<code>true</code>or<code>false</code></p>
<p>有可能:
1. 鉴权传递的参数有问题, 例如 id 错误/id 格式错误/未传递<code>_bk_iam_path_</code>导致拓扑类权限执行失败/少传递了资源某些属性
2. 用户的确没有该权限, 用户权限过期/退出组织/其所在部门退出组织等这类, 对应权限将被回收.</p>
<p>如果自己无法确定, 可以提单, 请将<code>debug</code>详情附到单据中.(注意 debug 中的敏感信息, 例如 app_code/app_secret 等提单是需要去掉)</p>
<h2 id="debug">附: 鉴权接口 debug 说明</h2>
<p>目前策略查询及鉴权接口, 调用支持 <code>debug</code>, 用于接入系统在接入调试期间对接口进行<code>debug</code></p>
<p>debug 接口将返回本次请求的上下文/执行详情/报错等信息</p>
<p>可以根据 debug 信息, 查看每条策略的执行结果, 确认接口执行正确性</p>
<p>注意: <strong>仅供调试用, 不要用在正式环境, 禁止用在生产逻辑</strong> (不能用在生产; 会导致对应接口性能急剧下降)</p>
<h3 id="_3">协议</h3>
<p>在接口 url 中加入参数<code>?debug=true&amp;force=true</code></p>
<pre class="codehilite"><code class="language-bash">http://{IAM_HOST}/api/v1/policy/query?debug=true&amp;force=true

http://{IAM_HOST}/api/v1/policy/auth?debug=true&amp;force=true</code></pre>


<p>返回内容:</p>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;data&quot;: {},
    &quot;debug&quot;: {
        &quot;time&quot;: &quot;2020-04-20T19:53:58.548923+08:00&quot;,
        &quot;context&quot;: {        # 上下文
            &quot;action&quot;: {},    #     Action信息
            &quot;policies&quot;: [    #     使用到的所有策略列表
                {
                &quot;ID&quot;: 4,    # Policy的ID
                }
            ],
            &quot;resources&quot;: [],  #   Resource资源信息
            &quot;subject&quot;: {},     #   Subject用户信息
            &quot;system&quot;: &quot;bk_cmdb&quot;   # 系统
        },
        &quot;steps&quot;: [             # 执行的步骤信息
            {
                &quot;index&quot;: 1,
                &quot;name&quot;: &quot;Fetch action details&quot;
            },
        ],
        &quot;evals&quot;: {            # 每条策略执行结果, key为PolicyID, 状态 paas/nopaas/unknown
            &quot;4&quot;: &quot;pass&quot;
        },
        &quot;error&quot;: &quot;&quot;           # 具体报错信息
    },
    &quot;message&quot;: &quot;ok&quot;
}</code></pre>


<ul>
<li>相对于正常接口, debug 接口多返回一个 debug 字段</li>
<li>time: 时间</li>
<li>context: 上下文<ul>
<li>system: 系统</li>
<li>subject: 用户</li>
<li>action: 操作</li>
<li>resources: 资源</li>
<li>policies: 计算用到的所有策略</li>
</ul>
</li>
<li>steps: 执行步骤</li>
<li>evals: 策略执行结果<ul>
<li>pass,  成功</li>
<li>nopass, 失败</li>
<li>unknown, 未知, 提前返回没有计算到这条策略</li>
</ul>
</li>
<li>error: 报错</li>
</ul><h1 id="_1">模型注册相关</h1>
<h2 id="1-systemprovider_config-healthz">1. system.provider_config 的 healthz 字段说明</h2>
<p>注册系统的时候, 除了 host/auth, 还需要提供 healthz</p>
<p>背景: 权限中心 SaaS 上用户配置权限时会依赖于接入系统的 <code>资源拉取接口</code>; 如果接入系统异常导致对应接口不可用, 那么在 SaaS 上, 用户将无法申请权限. 此时, 需要定期检查接入系统是否健康, 用于展示/监控/告警/提示用户等</p>
<p>注意: 
- 非必填, 不填的话, 会使用 <code>system.provider_config.host + ""</code> (注意不设置是空的)
- 注意这个接口不能带鉴权, 报错信息不能带敏感信息
- 这个 healthz 接口不一定是系统层面全局的 healthz, 范围不一样. 例如全局系统依赖 redis 不可用, healthz 报错, 但是不影响提供给 IAM 的 api, 此时 IAM 调用的 healthz 应该是正常的;</p>
<p>示例:</p>
<pre class="codehilite"><code class="language-json">{
    &quot;id&quot;: &quot;bk_cmdb&quot;,
    &quot;name&quot;: &quot;配置平台&quot;,
    &quot;name_en&quot;: &quot;CMDB&quot;,
    &quot;description&quot;: &quot;配置平台是一个...&quot;,
    &quot;description_en&quot;: &quot;CMDB is a...&quot;,
    &quot;clients&quot;: &quot;bk_cmdb,cmdb&quot;,
    &quot;provider_config&quot;: {
        &quot;host&quot;: &quot;http://cmdb.service.consul&quot;,
        &quot;healthz&quot;: &quot;/api/v1/healthz&quot;
        &quot;auth&quot;: &quot;basic&quot;
    }
}</code></pre>


<h2 id="2-ignore_iam_path">2. 注册操作的实例视图时, ignore_iam_path   有什么作用</h2>
<p>是否配置的权限忽略路径,   <a href="../../../Reference/API/02-Model/00-Concepts.md">名词及概念</a> 中的 ignore_iam_path 说明;</p>
<h2 id="3-id-32">3. 问题 操作 ID 32位限制是否会考虑放开?</h2>
<p>不会!</p>
<p>action_id 是唯一标识, 对于一个系统来说是枚举的, 32 位理论上可以支持超过所有系统的场景.</p>
<p>如果操作是<code>用户侧</code>配置的, 不可控, 建议给用户输入的信息做处理, 例如用户输入一串hash入库后生成一个唯一主键,  操作id为 <code>xxxx_{primary_key}</code> , 这个值只用于鉴权, 不需要可读性;</p>
<h2 id="4-action">4. 一个系统内最多能注册多少个action?</h2>
<p>具体见 <a href="../../../Explanation/07-Limit.md">说明: 权限中心限制</a></p>
<h2 id="5-resource">5. 注册一套系统, 能否针对不同的 resource 配置不同的回调域名?</h2>
<p>一套系统的, 只能有一个回调域名</p>
<p>背后如果是多个应用提供者的话, 需要自行转发过去, 例如使用网关或Nginx.</p>
<p>如果用多个系统, 由某个系统A管公共的权限, 
另一个系统 B 想要在页面上用到 A 管的公共权限, 将 B 的app_code注册为 A 的clients即可, 鉴权的时候可以调用 A 的鉴权接口;</p>
<h2 id="6-action-name">6. 模型注册: action name是否允许重复?</h2>
<p>不允许</p>
<h2 id="7">7. 新建关联配置/常用操作/操作组等, 能否增量更新?</h2>
<p>不支持增量, 本质上是一个json, 每个元素没有id的, 后台无法识别增删了哪些东西, 只能全覆盖</p><h1 id="_1">资源反向拉取相关</h1>
<h2 id="1-token">1. 权限中心<code>资源反向拉取</code>调用接入系统接口拉取资源时的 token 如何获取</h2>
<p>调用接口获取, 详细文档见  <a href="../../../Reference/API/01-Overview/03-APIAuth.md">系统间接口鉴权</a> / <a href="../../../Reference/API/02-Model/16-Token.md">系统 token 查询 API</a></p>
<p>建议缓存在内存中(确保升级/重启时重新拉取), 不建议放 redis 中(安全问题/更新未重新拉取)</p>
<h2 id="2">2. 资源反向拉取接口各自对应页面上哪些展示? 什么时候会被调用?</h2>
<ul>
<li>fetch_instance_info <strong>无权限申请</strong>/新建关联/跨系统资源依赖等场景, 会到接入系统拉取资源信息;<ul>
<li>无权限申请流程，生成无权限url，跳转权限中心<strong>提交申请单</strong>时会触发回调</li>
</ul>
</li>
<li>list_instance_by_policy 权限预览[前端暂未实现, 可以暂时不实现, 直接返回空]</li>
</ul>
<h2 id="3-fetch_instance_info">3. fetch_instance_info的作用是什么?</h2>
<p>无权限申请及其他权限申请场景, 接入系统生成提交的数据, 可能经过前端跳转或者被工具劫持, 可以将表单中资源 ID/名称等进行修改.</p>
<p>这样会带来安全风险, 申请资源 ID 是<code>核心业务 1</code>, 名称却是<code>非核心业务a</code>, 审批人无法识别id与名称是否匹配, 审批通过后有越权风险.</p>
<p>所以, 在数据进入申请审批流程, 或者授权流程, 权限中心会回调接入系统<code>fetch_instance_info</code>, 获取id及名称, 与提交的数据校验是否一致</p>
<h2 id="4-fetch_instance_info-parentid">4. fetch_instance_info 能给到父节点的parentID吗?</h2>
<p>不能! 
fetch_instance的时候只有id列表，入口有无权限申请/页面申请/授权api等，这时候id是离散的，权限中心并不知道这批id的上级是什么</p>
<h2 id="5-fetch_instance_info-idid">5. fetch_instance_info 的id列表为什么会有已经被删除的资源id?</h2>
<p>用户组的配置权限的时候, 会通过<code>list_instance</code>拉取到接入系统的资源列表, 配置权限, 此时保存了<code>资源 id</code></p>
<p>但是接入系统删除资源时并不会通知权限中心, 此时用户在修改已有策略的时候, 会触发回调.</p>
<p>接入系统应该过滤掉已经被删除的id, 只返回存在的. 例如
批量查 100 个, 如果其中有 3 个被删除, 返回另外 97 个.(不要500/404, 这是个批量接口, 需要确保其他数据正常返回)</p>
<p>(未来权限中心会增强这个协议, 支持识别被删除的资源, 做主动策略清理)</p>
<h2 id="6-list_instance">6. list_instance 的作用是什么?</h2>
<p>在配置权限页面, 资源是以列表的方式展示给用户的, 并且, 如果存在上下级关系, 例如点击业务, 展开展示业务下的主机列表.</p>
<p><code>list_instance</code>, 参数是上一级的<code>parent</code>的<code>type/id</code>, 拉取当前层级的资源列表</p><h1 id="_1">鉴权及策略查询相关</h1>
<h2 id="1-apiv1policyquery-resources">1. <code>/api/v1/policy/query</code> 接口是否可以不传资源(resources)</h2>
<p>可以
- 如果传了具体资源, 那么会返回 <code>用户+操作+这个资源</code>符合的所有策略(此时相当于拿传递的资源带入计算), 数据量小, 性能相对高一些;
- 如果不传资源, 那么会返回<code>用户+操作</code>的所有策略; 数量可能比较大, 接口传输数据量比较大, 性能相对会低一些; 拿到策略后, 接入系统需要自己把资源带入策略表达式计算. 可以用于一些批量的场景, 例如批量鉴权<code>用户-查看</code> 100 台主机的权限, 不传资源拉回来, 将 100 台主机资源带入遍历计算. (只需要一次策略查询)</p>
<h2 id="2-resources">2. 鉴权相关接口协议中 resources 字段代表一个资源</h2>
<ul>
<li>resources 是一个列表</li>
<li>resources 代表一个资源</li>
</ul>
<p>详细说明: <a href="../../../Reference/API/01-Overview/02-APIBasicInfo.md">接口协议中 resources 字段说明</a></p>
<h2 id="3-admin-any">3. 为什么 admin 用户所有策略查询返回的都是 any</h2>
<p>admin 是超级管理员, 默认有所有权限, 所以鉴权/策略查询得到的策略都是<code>{ op=any, field=, value=}</code>
进行接入验证/测试联调时, 避免使用 admin 用户.</p>
<p>用一个具体的用户, 申请权限, 测试</p>
<h2 id="4-any">4. 一个无关联资源类型的权限, 如果一个用户有权限的话返回的表达式是 any</h2>
<p>是的, <code>{ op=any, field=, value= }</code></p>
<h2 id="5-_bk_iam_path_">5. 使用实例视图展示拓扑配置了权限, 为什么返回的策略中有<code>_bk_iam_path_</code></h2>
<p>关于<code>_bk_iam_path_</code>, 可以查看 <a href="../../../Explanation/04-BkIAMPath.md">说明: 资源拓扑<code>_bk_iam_path_</code></a></p>
<p>当接入系统支持以<code>拓扑</code>配置权限, 那么勾选中间节点的时候, 会产生一个拓扑链路, 这个链路表示是<code>怎么选</code>到的资源, 即, 有这个路径下的资源的相关权限.</p>
<p>表达式中, 使用<code>_bk_iam_path_</code>来存储拓扑链路, 例如 <code>/biz,bk/set,sz/module,paas/</code> 表示 <code>业务-蓝鲸 -&gt; 集群-深圳 -&gt; 模块-paas</code></p>
<h2 id="6">6. 使用一个用户测试, 在我的权限里面没有对应权限, 但是实际上页面却是有权限操作的</h2>
<p>权限来源:
- 自定义申请
- 个人加入用户组权限 =&gt; 默认继承用户组权限
- 个人加入部门, 部门加入用户组 =&gt; 默认继承用户组权限</p>
<p>所以, [我的权限]-[自定义权限]中看不到, 并不一定没有权限, 需要检查 [用户组权限]</p><h1 id="_1">环境相关</h1>
<h2 id="1-saas">1. SaaS 如何获取和访问权限中心?  应该用哪个环境变量读取权限中心访问地址</h2>
<p>SaaS 在部署时, 已注入权限中心相关的环境变量. 
- <code>BK_IAM_V3_APP_CODE</code>  (权限中心 SaaS 的 app_code, 用于跳转到权限中心的 URL 拼接) 
- <code>BK_IAM_V3_INNER_HOST</code> (权限中心后台的访问地址)</p>
<p>具体可以阅读 <a href="../../../Reference/API/01-Overview/01-BackendAPIvsESBAPI.md">后台 API 和 ESB API 说明</a></p>
<h2 id="2-404">2. 调用接口 404</h2>
<p>文档中出现的接口都是存在的接口, 如果调用接口出现 404</p>
<p>一般是如下原因:
1. 访问地址配置错误, 接口分为后台 API 和 ESB API, 二者的访问地址是不一样的. 具体见 <a href="../../../Reference/API/01-Overview/01-BackendAPIvsESBAPI.md">后台 API 和 ESB API 说明</a>
2. URL 复制或拼接错误(需要再次核对)</p><h1 id="sdk">SDK 相关</h1>
<h2 id="1-iam-python-sdk">1. 怎么把 iam-python-sdk 的日志落地项目</h2>
<p>需要增加项目的 logging 配置, 具体见文档 <a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/docs/usage.md#%E6%B5%81%E6%B0%B4%E6%97%A5%E5%BF%97">流水日志</a></p>
<h2 id="2-python-sdk-debug">2. 怎么开启 python-sdk 的 debug</h2>
<p>详细内容见 <a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/docs/usage.md#api-debug">5.1 开启 debug 及配置流水日志</a></p>
<p><strong>注意</strong> :  <code>debug</code> 仅在调试阶段开启, 生产环境请关闭( <code>iam_looger.setLevel(logging.ERROR)</code> );</p>
<pre class="codehilite"><code class="language-python">from iam import IAM, Request, Subject, Action, Resource

import sys
import logging
iam_logger = logging.getLogger(&quot;iam&quot;)
iam_logger.setLevel(logging.DEBUG)

debug_hanler = logging.StreamHandler(sys.stdout)
debug_hanler.setFormatter(logging.Formatter('%(levelname)s [%(asctime)s] [IAM] %(message)s'))
iam_logger.addHandler(debug_hanler)</code></pre><h1 id="do_migrate">do_migrate 相关</h1>
<h2 id="1-do_migrate-upsert_action_groups">1. do_migrate 执行 upsert_action_groups 为什么只有最后一个生效</h2>
<p>全局只有一个<code>action_groups</code>列表，只做一次操作，配置多个<code>upsert_action_groups</code>每一个都会覆盖前面的导致最后只有一个生效</p>
<p>所以应该用<code>action_groups</code>列表来支持多个操作而不是调用多次<code>upsert_action_groups</code></p>
<h2 id="2-do_migrate-conflict-xxxx-already-exists">2. do_migrate 执行结果 conflict: xxxx  already exists</h2>
<p><code>ID/中文名/英文名</code>等, 要求系统内唯一, 如果出现<code>conflict: xxxx already exists</code>, 说明之前注册过, 现在插入的和之前的有冲突.</p>
<p>具体每种资源的限制, 详见 <a href="../../../Reference/API/02-Model/00-API.md">模型注册 API</a></p>
<p>需要:
1. 如果是不同资源, 需要确保不冲突
2. 如果是同一个资源变更 ID, 需要先删除老的, 再插入新的</p>
<h2 id="3-do_migrate-django-iam-migration">3. do_migrate 如果我使用 django 框架怎么进行 iam migration</h2>
<p>可以使用 python sdk 中集成到 django migration 中, 具体文档: <a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/docs/usage.md#2-iam-migration">iam-python-sdk</a></p>
<h2 id="4-do_migrate">4. do_migrate 是否可以重复执行同一个文件</h2>
<p><code>add_*</code> 的操作会报错, 因为第二次执行时跟已有资源冲突了. </p>
<p><code>update_*</code>操作需要确保资源存在</p>
<p><code>upsert_*</code> 操作不存在则创建/存在则更新. 建议尽量使用<code>upsert</code>操作</p>
<h2 id="5-apigateway-do_migrate">5. 已经有最新版的 APIGateway 且有权限中心网关, do_migrate如何切换?</h2>
<p>注册权限模型也需要调用APIGateway接口，  需要替换一下<a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/0d9b67baa24144d3c84be12cc3cd4adfd487b74c/iam/contrib/iam_migration/utils/do_migrate.py">do_migrate.py文件</a> </p>
<p>然后使用新命令执行，</p>
<p><code>-t</code> 换成apigateway的 URL 之后, 多加一个 <code>--apigateway</code></p>
<p>新命令样例如下：</p>
<pre class="codehilite"><code>python3 do_migrate.py -t http://bk-iam.apigw.blueking.com/prod -f ./demo_model.json -a &quot;demo&quot; -s &quot;c2cfbc92-28a2-420c-b567-cf7dc33cf29f&quot; --apigateway</code></pre><h1 id="_1">使用场景相关</h1>
<h2 id="1-1000">1. 怎么实现批量鉴权, 一个用户是否有查看 1000 台主机的权限</h2>
<ul>
<li>调用策略查询<code>/api/v1/policy/query</code>接口<ul>
<li>传了 resource, 相当于权限中心会基于表达式做第一遍计算, 缩小策略数量</li>
<li>不传 resource, 会把所有策略返回去</li>
</ul>
</li>
<li>不传 resource, 获取得到所有策略</li>
<li>将 1000 台主机 for 循环逐一带入求值</li>
<li>此时, 相当于做一次策略查询, 执行 1000 次计算(内存表达式求值性能很高)</li>
</ul>
<h2 id="2">2. 配置权限的时候, 怎么控制只能选择实例, 不需要配置属性</h2>
<p>action 操作注册时, <code>related_resource_types[i].selection_mode=instance</code>即可, 具体见文档  <a href="../../../Reference/API/02-Model/13-Action.md">操作(Action) API</a></p>
<p>如果只需要属性,  <code>selection_mode=attribute</code>; 如果两者都要<code>selection_mode=all</code></p>
<h2 id="3-10000">3. 能否放开单个用户配置超过 10000 个实例的权限</h2>
<p>10000 个限制<strong>不会放开</strong></p>
<p>具体见 <a href="../../../Explanation/06-LargeScaleInstances.md">大规模实例级权限限制具体说明和对应处理方案</a></p>
<h2 id="4">4. 授权接口的机制是怎样的? 重复调用会不会有问题?</h2>
<p>增量更新, 会同已有权限进行合并</p>
<p>重复调用不会有问题</p>
<h2 id="5">5. 用户组管理时, 组名是唯一的吗?</h2>
<p>用户组名是分级管理员下唯一</p>
<h2 id="6">6. 如果调用权限中心接口报错, 应该怎么提示给用户?</h2>
<p>假设接入系统调用接口报错, 需要显式提示并且打日志: <strong>记录详细错误信息, 并把错误信息/原因暴露给用户</strong></p>
<p>相关信息:
- 请求时间
- method
- url
- response status
- response body
- requestID
- 报错堆栈</p>
<p>有很多因素, 例如网络错误/超时/请求数据错误/接口 500 /接口 502等等.</p>
<p>一定不能: 吞掉异常或者没有打日志, 直接弹窗提示请联系权限中心(这是无法排查的, 调用失败日志都在接入系统, 请求可能根本没到权限中心)</p><h1 id="_1">日志</h1>
<h1 id="saas">权限中心 SaaS 日志说明</h1>
<table>
<thead>
<tr>
<th>文件名</th>
<th>说明</th>
<th>日志级别</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>bk_iam.log</td>
<td>后台日志</td>
<td>info</td>
<td>IAM SaaS 本身进程打印日志, 包含基本运行信息 (IAM SaaS 服务报错)</td>
</tr>
<tr>
<td>uwsgi.log</td>
<td>API 请求 Uwsgi 日志</td>
<td>info</td>
<td>默认是所有请求流水日志，特别是 500 等系统异常，可直接查看该日志</td>
</tr>
<tr>
<td>component.log</td>
<td>请求第三方接口日志</td>
<td>info</td>
<td>调用第三方系统接口流水日志，包括对 IAM 后台服务、用户管理、ITSM 以及<code>接入系统回调接口</code></td>
</tr>
<tr>
<td>celery.log</td>
<td>异步任务日志</td>
<td>info</td>
<td>后台异步任务日志，包括<code>同步组织架构</code>、续期通知等</td>
</tr>
</tbody>
</table>
<h1 id="_2">权限中心后台日志说明</h1>
<p>如果请求 <code>url = /api/c/compapi/v2/iam/[application | authorization]</code>, 那么需要从开发者中心 S-mart 应用查询相关的日志(<code>开发者中心-Smart应用-权限中心V3-日志查询</code>)</p>
<p>如果请求 <code>url = /api/v1/[model | policy | systems]</code>, 那么需要从后台日志查对应的<code>request_id</code>(注意可能部署在多台机器)</p>
<table>
<thead>
<tr>
<th>文件名</th>
<th>说明</th>
<th>日志级别</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>iam.log</td>
<td>后台日志</td>
<td>info</td>
<td>IAM 系统本身进程打印日志, 包含基本运行信息 (IAM 后台服务报错)</td>
</tr>
<tr>
<td>iam_api.log</td>
<td>鉴权 API 流水日志</td>
<td>info</td>
<td>接入系统使用<code>/api/v1/query</code>进行鉴权的流水日志; 默认记录所有鉴权请求日志 (接入系统鉴权报错)</td>
</tr>
<tr>
<td>iam_sql.log</td>
<td>SQL 日志</td>
<td>info</td>
<td>SQL 执行语句日志;  如果日志级别是 debug, 记录所有日志, 否则, 只记录执行时间大于 20ms 的 SQL 语句 <strong>注意: 如果使用 debug 将导致服务性能大幅下降</strong></td>
</tr>
<tr>
<td>iam_audit.log</td>
<td>模型注册流水日志</td>
<td>info</td>
<td>接入系统使用<code>/api/v1/model</code>进行模型注册的流水日志 (接入系统注册模型报错)</td>
</tr>
<tr>
<td>iam_web.log</td>
<td>SaaS 访问流水日志</td>
<td>info</td>
<td>IAM 前端 SaaS 调用后台接口<code>/api/v1/web/</code>的流水日志; 默认打印所有 SaaS 请求日志 (IAM SaaS App 访问后台报错)</td>
</tr>
<tr>
<td>iam_component.log</td>
<td>请求第三方接口日志</td>
<td>error</td>
<td>调用第三方系统接口流水日志;   如果日志级别是 debug, 打印所有日志, 否则, 只记录非 200 及发生报错的请求日志 <strong>注意: 如果使用 debug 将导致跨系统资源依赖相关的鉴权性能下降</strong></td>
</tr>
</tbody>
</table><h1 id="_1">提单模板</h1>
<p>注意事项:
1. 提单前, 请确保已经根据<code>问题排查</code>文档进行过问题排查(常见问题/错误码/FAQ 等等)
2. 请记录已获取的信息, 日志, 以及做过哪些定位, 结果是什么
3. 之后提单, 根据模板要求填写详细信息, 给到 IAM 开发</p>
<h2 id="saas">权限中心 SaaS 页面报错提单模板</h2>
<p>前端大概率是 <a href="SaaS-Callback.md">常见: SaaS 回调接入系统失败</a> 的问题, 先根据这个文档确认并找相关人员解决.</p>
<p>如果页面看到接口 500, 请到权限中心 SaaS 捞取 500 日志后再提单</p>
<p>如果不是上述文档中的问题</p>
<ul>
<li>标题: <code>[权限中心 SaaS] xxx 页面报错</code></li>
<li>内容:</li>
</ul>
<pre class="codehilite"><code class="language-bash">环境: xxxx

现象描述: xxxxxx
报错截图: xxxx
报错信息: (需要将提示框中信息复制粘贴出来)
复现步骤: xxxxx

后端报错日志: (如果是接口 500)</code></pre>


<h2 id="_2">接口调用报错提单模板</h2>
<ul>
<li>标题: <code>[xx系统] 调用权限中心错误xxxxxxx</code></li>
<li>内容:</li>
</ul>
<pre class="codehilite"><code class="language-bash">系统: xxxx
环境: 上云版/企业版xx环境/社区版xx环境

现象描述: xxxxxxxxxxxx
预期: xxxxxxxxxxx
复现步骤: xxxxxxxxxxxx [务必附加]
截图: [better to have]

请求基本信息:
- method: POST
- path: http://xxxxxx/api/v1/policy/query
- request_body: `{xxxx}`

响应基本信息:
- status code: 2000
- response body: `{}`
- request_id: `xxxxxxxxxxx`

从权限中心查询request_id日志结果 (具体见本文档   附录: 权限中心的日志)</code></pre>


<p>如果调用方无法提供上述信息, 那么打印记录详细的日志, 再提单!!!!!!(否则无法进行问题定位)</p>
<h2 id="_3">其他: 接入系统需要 记录详细日志</h2>
<p>接入系统调用逻辑需要记录以下信息: (<strong>以便在排查问题时提供</strong>)</p>
<ol>
<li>请求时间</li>
<li>请求基本信息: method / url / request body</li>
<li>响应基本信息: status code / response body(包含<code>code</code>和<code>message</code>)</li>
<li>响应 header 中的 <code>request_id</code> </li>
</ol><h1 id="iam-saas-debug-trace">IAM SaaS Debug Trace 接口</h1>
<h1 id="1">1. 背景</h1>
<p>为了方便客户快速定位错误信息, 降低问题定位的沟通成本, 权限中心 SaaS 提供了快速查询 Debug Trace 的相关接口</p>
<p>客户在发现 SaaS 使用过程中出现<code>未知错误</code>, 可以通过<code>request_id</code>查询到相关的调试信息, 提单时附加到单据中</p>
<p>如果发现后台定时任务出现异常也可以通过<code>task_id</code>查询到相关的调试信息, 如果找不到<code>task_id</code>, 可以通过<strong>日期</strong>来查询所有当天任务执行的调试信息</p>
<h1 id="2">2. 接口认证</h1>
<p>以下接口使用<code>HTTP Basic authentication</code>认证方式, 用户名: IAM SaaS 的<code>app_code</code>, 密码: IAM SaaS 的<code>app_secret</code></p>
<p><code>iam_saas_api_prefix</code>为权限中心 SaaS 部署后的地址(即蓝鲸权限中心页面访问地址), 例如<code>http://{{paas_domain}}/o/bk_iam</code></p>
<h1 id="3">3. 协议</h1>
<h2 id="31-request_idtask_id">3.1 通过 request_id/task_id 查询调试跟踪信息</h2>
<h4 id="url">URL</h4>
<blockquote>
<p>GET http://{iam_saas_api_prefix}/api/v1/debug/{request_id/task_id}/</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="center">字段</th>
<th align="center">类型</th>
<th align="center">是否必须</th>
<th align="center">位置</th>
<th align="center">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">request_id/task_id</td>
<td align="center">string</td>
<td align="center">是</td>
<td align="center">path</td>
<td align="center">请求 id/任务 id</td>
</tr>
</tbody>
</table>
<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json"># 请求debug信息数据
{
  &quot;data&quot;: {
    &quot;id&quot;: &quot;205310e3fe5548059ad386d7969b8161&quot;,  # request_id
    &quot;type&quot;: &quot;api&quot;,
    &quot;path&quot;: &quot;/api/v1/accounts/user/&quot;,  #  请求path
    &quot;method&quot;: &quot;post&quot;,  # 请求method
    &quot;data&quot;: {},  # request data
    &quot;exc&quot;: &quot;&quot;,  # 异常信息
    &quot;stack&quot;: [],  # 调用链信息
  },
  &quot;result&quot;: true,
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;OK&quot;
}

# celery任务debug信息
{
  &quot;data&quot;: {
    &quot;id&quot;: &quot;cdc04cd3-c91f-4a98-9772-f237e313e90c&quot;,  # 任务id
    &quot;type&quot;: &quot;task&quot;,
    &quot;name&quot;: &quot;backend.apps.role.tasks.role_group_expire_remind&quot;,  # 任务名称
    &quot;exc&quot;: &quot;&quot;,  # 异常信息
    &quot;stack&quot;: [],  # 调用链信息
  },
  &quot;result&quot;: true,
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;OK&quot;
}</code></pre>


<h2 id="32">3.2 通过日期查询后台任务调试跟踪信息</h2>
<h4 id="url_1">URL</h4>
<blockquote>
<p>GET http://{iam_saas_api_prefix}/api/v1/debug/?day={day}</p>
</blockquote>
<h4 id="parameters_1">Parameters</h4>
<table>
<thead>
<tr>
<th align="center">字段</th>
<th align="center">类型</th>
<th align="center">是否必须</th>
<th align="center">位置</th>
<th align="center">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">day</td>
<td align="center">string</td>
<td align="center">是</td>
<td align="center">query_string</td>
<td align="center">日期, 例如 20210101</td>
</tr>
</tbody>
</table>
<h4 id="response_1">Response</h4>
<pre class="codehilite"><code class="language-json">{
  &quot;data&quot;: [
      {
        &quot;id&quot;: &quot;cdc04cd3-c91f-4a98-9772-f237e313e90c&quot;,
        &quot;type&quot;: &quot;task&quot;,
        &quot;name&quot;: &quot;backend.apps.role.tasks.role_group_expire_remind&quot;,
        &quot;exc&quot;: &quot;&quot;,
        &quot;stack&quot;: [],
      }
  ]
  &quot;result&quot;: true,
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;OK&quot;
}</code></pre><h1 id="iam-debug-cli">IAM-Debug CLI</h1>
<h2 id="1">1. 背景</h2>
<p>在部署和运维权限中心的过程中, 可能会定位一些问题</p>
<p>如果通过查询数据库/日志/报错信息等方式, 那么整个问题排查成本会非常高</p>
<p>基于这个原因, 我们开发了<code>debug-cli</code>, 服务提供了相应的 debug api, 通过 cli 可以直接查询获取得到相关的信息(例如不需要自行去查询多个表拼凑信息, debug api 直接组合查询)</p>
<p>通过<code>debug-cli</code>, 运维可以按照文档步骤, 一步步执行, 获取结果, 通过结果快速定位问题.</p>
<h2 id="2">2. 使用简介</h2>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli help
A command tool for IAM debug.
You can use it to query the system model, policy data, user data, cache as so on.

Usage:
  iam-cli [command]

Available Commands:
  cache       Query policy or expression from cache
  healthz     call /healthz to check if the iam backend service is health
  help        Help about any command
  login       Login via app_code/app_secret of IAM
  ping        call /ping to check if the iam backend service is alive
  query       Query data of model/action/subject/policy
  use         The current system you want to query
  version     call /version to check the version of iam backend

Flags:
      --config string   config file (default is $HOME/.iam-cli.yaml)
  -h, --help            help for iam-cli
  -t, --toggle          Help message for toggle

Use &quot;iam-cli [command] --help&quot; for more information about a command.</code></pre>


<h2 id="3">3. 使用示例</h2>
<h3 id="31-login">3.1 登录 login</h3>
<blockquote>
<p>./iam-cli login http://{iam_host} {app_code} {app_secret}</p>
</blockquote>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli login http://{bkiam_address} bk_iam {bk_iam_saas_app_secret}
INFO: success</code></pre>


<h3 id="32">3.2 确认基本服务可用</h3>
<blockquote>
<p>./iam-cli [ping | version | healthz]</p>
</blockquote>
<p>分别确定服务可达/版本号/是否健康</p>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli ping
INFO: pong

$ ./iam-cli version
INFO: success
{
  &quot;buildTime&quot;: &quot;2021-01-15_05:50:01&quot;,
  &quot;commit&quot;: &quot;61a8cb2b2978c72c509ceb264fbfb7620a98173c&quot;,
  &quot;env&quot;: &quot;&quot;,
  &quot;goVersion&quot;: &quot;go version go1.14 linux/amd64&quot;,
  &quot;version&quot;: &quot;1.5.9&quot;
}

$ ./iam-cli healthz
INFO: ok</code></pre>


<h3 id="33">3.3 切换系统</h3>
<blockquote>
<p>./iam-cli use {system_id}</p>
</blockquote>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli use bk_paas
INFO: success</code></pre>


<h3 id="34">3.4 查询系统注册的权限模型</h3>
<blockquote>
<p>./iam-cli query [model | action]</p>
</blockquote>
<pre class="codehilite"><code class="language-bash">$  ./iam-cli query model

$ ./iam-cli query action</code></pre>


<h3 id="35-subject-policy">3.5 查询某个 subject 在系统下某个操作的 policy</h3>
<blockquote>
<p>./iam-cli query policy {subject_type} {subject_id} {action_id}</p>
</blockquote>
<pre class="codehilite"><code class="language-bash">./iam-cli query policy user admin access_developer_center
{
  &quot;field&quot;: &quot;&quot;,
  &quot;op&quot;: &quot;any&quot;,
  &quot;value&quot;: []
}</code></pre>


<h3 id="36-subject">3.6 查询某个 subject</h3>
<blockquote>
<p>./iam-cli query subject {subject_type} {subject_id}</p>
</blockquote>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli query subject group 1
{
  &quot;departments&quot;: [],
  &quot;errs&quot;: {},
  &quot;groups&quot;: null,
  &quot;subject&quot;: {
    &quot;id&quot;: &quot;1&quot;,
    &quot;pk&quot;: 43325,
    &quot;type&quot;: &quot;group&quot;
  }
}

$ ./iam-cli query subject user test1</code></pre>


<h3 id="37-policy-expression">3.7 查询缓存内的 policy 和 expression</h3>
<blockquote>
<p>./iam-cli cache policy {subject_type} {subject_id}                    # list all actions
./iam-cli cache policy {subject_type} {subject_id} {action_id}  # get one action
./iam-cli cache expression exprPK1 exprPK2 ...</p>
</blockquote>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli cache policy group 1 access_developer_center
{
  &quot;action_pk&quot;: 347,
  &quot;errs&quot;: [
    null,
    null
  ],
  &quot;expressions&quot;: [],
  &quot;notInCache&quot;: false,
  &quot;policies&quot;: [],
  &quot;subject_pk&quot;: 43325
}

./iam-cli cache expression 351 347
{
  &quot;err&quot;: null,
  &quot;expressions&quot;: null,
  &quot;noCachePKs&quot;: [
    351,
    347
  ],
  &quot;pks&quot;: [
    351,
    347
  ]
}</code></pre>


<h3 id="38-saas-login">3.8 SaaS 登录 login</h3>
<blockquote>
<p>./iam-cli saas login http://{iam_saas_host} {app_code} {app_secret}</p>
</blockquote>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli saas login http://{bkiam_saas_address} bk_iam {bk_iam_saas_app_secret}
INFO: success</code></pre>


<h3 id="39-saas">3.9 确认 SaaS 可用</h3>
<blockquote>
<p>./iam-cli saas ping</p>
</blockquote>
<p>去掉 SaaS 可达</p>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli saas ping
INFO: pong</code></pre>


<h3 id="310-saas-debug">3.10 查询 SaaS 的 Debug 信息列表</h3>
<blockquote>
<p>./iam-cli saas debug list 20210101</p>
</blockquote>
<p>查询<code>20210101</code>这一天 SaaS 的所有 debug 信息</p>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli saas debug list 20210101
[
  {
    &quot;id&quot;: &quot;cdc04cd3-c91f-4a98-9772-f237e313e90c&quot;,
    &quot;type&quot;: &quot;task&quot;,
    &quot;name&quot;: &quot;backend.apps.role.tasks.role_group_expire_remind&quot;,
    &quot;exc&quot;: &quot;&quot;,
    &quot;stack&quot;: [],
  }
]</code></pre>


<h3 id="311-request_idtask_id-debug">3.11 通过 request_id/task_id 查询单个请求的 Debug 信息</h3>
<blockquote>
<p>./iam-cli saas debug get {request_id/task_id}</p>
</blockquote>
<p>通过请求 ID 或者 Celery Task ID 查询 Debug 信息</p>
<pre class="codehilite"><code class="language-bash">$ ./iam-cli saas debug get 205310e3fe5548059ad386d7969b8161
{
  &quot;id&quot;: &quot;205310e3fe5548059ad386d7969b8161&quot;,  # request_id
  &quot;type&quot;: &quot;api&quot;,
  &quot;path&quot;: &quot;/api/v1/accounts/user/&quot;,  #  请求path
  &quot;method&quot;: &quot;post&quot;,  # 请求method
  &quot;data&quot;: {},  # request data
  &quot;exc&quot;: &quot;&quot;,  # 异常信息
  &quot;stack&quot;: [],  # 调用链信息
}</code></pre><h1 id="_1">部署及运维说明</h1>
<blockquote>
<p>VERSION: 1.1.1</p>
</blockquote>
<h2 id="_2">背景</h2>
<p>IAM, 权限中心; 作为蓝鲸智云基础服务之一, 整体服务对可用性要求非常高;</p>
<p>文档主要说明 IAM 的基础部署模式, 以及阐述监控项及故障点, 方便部署及运维.</p>
<h2 id="_3">交付包</h2>
<ul>
<li>SaaS 包: bk_iam_V1.0.0.tar.gz  (app_code=<code>bk_iam</code>)</li>
<li>后台包: <ul>
<li>部署目录: <code>__BK_HOME__/bkiam/</code></li>
<li>日志目录: <code>__BK_HOME__/logs/bkiam/</code></li>
<li>数据库: <code>bkiam</code></li>
<li>配置文件: <code>/etc/bkiam_config.yaml</code></li>
<li>supervisor 配置: <code>/etc/supervisor-bkiam.conf</code></li>
<li>consul 地址: <code>bkiam.service.consul</code></li>
<li>sql 初始化执行目录: <code>support-files/sql/*.sql</code></li>
</ul>
</li>
</ul>
<h2 id="_4">配置文件说明</h2>
<pre class="codehilite"><code class="language-yaml">debug: false    # 启动模式, 生产环境请设为false! 
                # 如果是true, 请求的日志会全量打印, 记录完整信息, 对性能影响比较大

server:
  host: {IP}      # 监听IP
  port: {PORT}    # 监听端口

  readTimeout: 300
  writeTimeout: 300
  idleTimeout: 180

# use comma ”,“ separated when multiple app_code
superAppCode: &quot;bk_iam&quot;    # SaaS AppCode, 不需要修改

databases:
  - id: &quot;iam&quot;            # 权限中心IAM的数据库配置
    host: &quot;{MYSQL_IP}&quot;
    port: {MYSQL_PORT}
    user: &quot;{MYSQL_USER}&quot;
    password: &quot;{MYSQL_PASSWORD}&quot;
    name: &quot;bkiam&quot;
    maxOpenConns: 200
    maxIdleConns: 50
    connMaxLifetimeSecond: 600

  - id: &quot;open_paas&quot;      # OpenPaaS数据库配置
    host: &quot;{MYSQL_IP}&quot;
    port: {MYSQL_PORT}
    user: &quot;{MYSQL_USER}&quot;
    password: &quot;{MYSQL_PASSWORD}&quot;
    name: &quot;open_paas&quot;

redis:
  - id: &quot;sentinel&quot;      # redis配置, 生产环境建议使用sentinel模式
    addr: &quot;{REDIS_SENTINEL_HOST}:{REDIS_SENTINEL_PORT}&quot;  # redis sentinel的服务地址
    password: &quot;{REDIS_PASSWORD}&quot;  # redis实例的密码
    db: 0                         # redis使用的db实例
    poolSize: 160
    dialTimeout: 3
    readTimeout: 1
    writeTimeout: 1
    masterName: &quot;{REDIS_MASTER_NAME}&quot;  # sentinel模式下MansterName
    sentinelPassword: &quot;&quot;  # sentinel模式下支持配置sentinel密码

logger:    # 日志配置, 以下path字段可以自行更新为日志路径
  system:   
    level: info
    writer: file
    settings: {name: iam.log, size: 100, backups: 10, age: 7, path: ./}
  api:
    level: info
    writer: file
    settings: {name: iam_api.log, size: 100, backups: 10, age: 7, path: ./}
  sql:
    level: info
    writer: file
    settings: {name: iam_sql.log, size: 100, backups: 10, age: 7, path: ./}
  audit:
    level: info
    writer: file
    settings: {name: iam_audit.log, size: 500, backups: 20, age: 365, path: ./}
  web:
    level: info
    writer: file
    settings: {name: iam_web.log, size: 100, backups: 10, age: 7, path: ./}
  component:
    level: error
    writer: file
    settings: {name: iam_component.log, size: 100, backups: 10, age: 7, path: ./}</code></pre>


<p>其中 redis 支持使用单实例(standalone 模式)</p>
<pre class="codehilite"><code class="language-yaml">redis:
  - id: &quot;standalone&quot;                   # redis配置
    addr: &quot;{REDIS_HOST}:{REDIS_PORT}&quot;  # redis的服务地址
    password: &quot;{REDIS_PASSWORD}&quot;       # redis实例的密码
    db: 0                              # redis使用的db实例
    poolSize: 160
    dialTimeout: 3
    readTimeout: 1
    writeTimeout: 1
    masterName: &quot;&quot;                     # 置空</code></pre>


<hr />
<h2 id="1">1. 高可用部署</h2>
<h3 id="11">1.1 对机器的要求</h3>
<p>IAM 是一个 <code>CPU密集型</code>  + <code>IO密集型</code>的服务; </p>
<ul>
<li>流量大: 本身要处理请求, 同时依赖 Redis/MySQL; 需要确保带宽及网卡</li>
<li>计算密集: 建议提供 4C8G 的机器; 无状态可以多机水平扩展; 高可用至少部署 3 台机器</li>
<li>IO 密集: 磁盘预留 15G 左右空间</li>
</ul>
<h3 id="12">1.2 依赖</h3>
<p>由于权限中心是最基础的组件之一(几乎所有产品依赖), 数据重要性高, 同时对性能要求高; </p>
<p>所以对<code>MySQL</code>和<code>Redis</code>的性能及可靠性有要求</p>
<ol>
<li>数据库: <ul>
<li>要求: <strong>独立实例</strong></li>
<li>需要有<strong>主从</strong>, 且需要定时<strong>数据备份</strong>! </li>
<li>做好 MySQL 的监控及故障切换预案</li>
<li>必要时, 考虑冷备方案</li>
</ul>
</li>
<li>Redis: <ul>
<li>要求: <strong>独立实例</strong></li>
<li>支持 Redis 单实例, 但是强烈建议生产环境使用<strong>sentinel 模式</strong>! </li>
<li>做好 Redis 的监控以及故障切换</li>
<li><code>注意</code>: 不能使用 Redis twemproxy 集群方案, 因为 IAM 大量使用了 pipeline, 而 twemproxy 不支持</li>
<li>仅做缓存用途, 不需要做数据持久化或备份;</li>
</ul>
</li>
</ol>
<p>独立实例, 隔离防止受其他因素影响, 也方便进行<code>高可用扩展</code>, <code>监控</code>, <code>扩容</code>, <code>问题排查</code>等</p>
<h3 id="13">1.3 默认方案: 无状态多实例部署</h3>
<blockquote>
<p>部署 3 个以上实例, 实例等价, 使用相同的 MySQL 和 Redis</p>
</blockquote>
<p>建议: 使用高可用部署方案, 启动至少 3 个 IAM 实例, 配置统一的接入层, 支持负载均衡, 并确保接入层本身高可用</p>
<p><img alt="enter image description here" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/OPS/1.png" /></p>
<h3 id="14">1.4 读写分离方案</h3>
<p>正常情况下, 使用<code>默认方案: 无状态多实例部署</code>能满足大部分需求, 只有某些场景下才需要考虑<code>读写分离方案</code>; 由于复杂度较高, 需谨慎</p>
<blockquote>
<p>当单一数据库成为瓶颈, 支持读写分离部署拓扑, 不同实例连接不同的 mysql</p>
</blockquote>
<p>读写分离:
- 读流量: <code>/api/v1/policy</code>开头的请求流量, 转发到<code>连接从库</code>的实例
- 写流量: 非<code>/api/v1/policy</code>开头的请求流量, 转发到<code>连接主库</code>的实例</p>
<p><img alt="enter image description here" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/OPS/2.png" /></p>
<hr />
<h2 id="2">2. 日志</h2>
<p>日志目录: <code>__BK_HOME__/logs/bkiam/</code></p>
<table>
<thead>
<tr>
<th>文件名</th>
<th>说明</th>
<th>日志级别</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>iam.log</td>
<td>后台日志</td>
<td>info</td>
<td>IAM 系统本身进程打印日志, 包含基本运行信息 (IAM 后台服务报错)</td>
</tr>
<tr>
<td>iam_api.log</td>
<td>鉴权 API 流水日志</td>
<td>info</td>
<td>接入系统使用<code>/api/v1/query</code>进行鉴权的流水日志; 默认记录所有鉴权请求日志 (接入系统鉴权报错)</td>
</tr>
<tr>
<td>iam_sql.log</td>
<td>SQL 日志</td>
<td>info</td>
<td>SQL 执行语句日志;  如果日志级别是 debug, 记录所有日志, 否则, 只记录执行时间大于 20ms 的 SQL 语句 <strong>注意: 如果使用 debug 将导致服务性能大幅下降</strong></td>
</tr>
<tr>
<td>iam_audit.log</td>
<td>模型注册流水日志</td>
<td>info</td>
<td>接入系统使用<code>/api/v1/model</code>进行模型注册的流水日志 (接入系统注册模型报错)</td>
</tr>
<tr>
<td>iam_web.log</td>
<td>SaaS 访问流水日志</td>
<td>info</td>
<td>IAM 前端 SaaS 调用后台接口<code>/api/v1/web/</code>的流水日志; 默认打印所有 SaaS 请求日志 (IAM SaaS App 访问后台报错)</td>
</tr>
<tr>
<td>iam_component.log</td>
<td>请求第三方接口日志</td>
<td>error</td>
<td>调用第三方系统接口流水日志;   如果日志级别是 debug, 打印所有日志, 否则, 只记录非 200 及发生报错的请求日志 <strong>注意: 如果使用 debug 将导致跨系统资源依赖相关的鉴权性能下降</strong></td>
</tr>
</tbody>
</table>
<hr />
<h2 id="3">3. 监控</h2>
<blockquote>
<p>确保所有服务有监控</p>
</blockquote>
<p>请根据 IAM 提供的监控入口, 对 IAM 整体服务的可用性进行监控</p>
<h3 id="31-ping">3.1 实例是否可达 <code>/ping</code></h3>
<p>测试服务可达/网络 ok, 返回时间应<code>&lt;100ms</code></p>
<pre class="codehilite"><code class="language-bash">$ curl http://{IAM_HOST}/ping
{&quot;message&quot;:&quot;pong&quot;}</code></pre>


<h3 id="32-healthz">3.2 实例是否健康 <code>/healthz</code></h3>
<p>测试服务健康度, 会检查 IAM 的依赖是否正常:
1. mysql
2. redis</p>
<p>返回值:
- 200: 正常
- 500: 异常, 消息体包含信息</p>
<pre class="codehilite"><code class="language-bash">$ curl http://{IAM_HOST}/healthz
ok</code></pre>


<h3 id="33-prometheus-metrics">3.3 Prometheus <code>/metrics</code></h3>
<p>可以将多个实例的<code>/metrics</code>接入 Promethues, 做统一的监控</p>
<p>可以监控包括:
1. 实例是否存活
2. 实例的运行状态: 内存/gc 等 (单机性能/是否需要扩容)
3. 实例的请求处理数量/响应时间分布: 排查慢请求问题</p>
<pre class="codehilite"><code class="language-bash">curl http://{IAM_HOST}/metrics</code></pre>


<p>可以配置图表:</p>
<p>Request Total</p>
<pre class="codehilite"><code class="language-bash">sum(increase(api_requests_total{job=&quot;bkiam&quot;, instance=&quot;${instance}&quot;}[1m]))</code></pre>


<p>API Response Time Quantile [1m]</p>
<pre class="codehilite"><code class="language-bash">histogram_quantile(0.95, sum(rate(api_request_duration_milliseconds_bucket{job=&quot;bkiam&quot;, instance=&quot;${instance}&quot;}[1m])) by (le, instance))</code></pre>


<h3 id="34">3.4 数据库监控</h3>
<p>监控 IAM 连接的对应数据库实例的 mysql</p>
<ol>
<li>慢查询, 详细日志</li>
<li>事务及锁情况</li>
</ol>
<p>监控表行数过大</p>
<ul>
<li><code>policy</code> 策略表</li>
<li><code>expression</code> 表达式表</li>
<li><code>subject</code> 用户表</li>
<li><code>subject_relation</code> 用户组织关系表</li>
</ul>
<h3 id="35-redis">3.5 Redis 监控</h3>
<p>监控 IAM 使用 Redis 服务的</p>
<ol>
<li>服务可用</li>
<li>响应速度</li>
<li>连接数/key 数量/内存占用</li>
<li>key hit/miss 比例</li>
</ol>
<h3 id="36">3.6 日志监控</h3>
<p>将 iam 的所有日志使用<code>日志采集</code>相关组件, 采集上报后做相关的日志关键字监控</p>
<p>例如:
- 可以监控 <code>iam.log</code> 中 <code>level=error</code> 的日志
- 监控<code>iam_api.log</code> 中 <code>status!=200</code> 的日志</p>
<h3 id="37-sentry">3.7 Sentry 支持</h3>
<p>如果有 Sentry 服务, 可以将权限中心后台服务接入, 异常及其详情会上报到 Sentry 中</p>
<pre class="codehilite"><code class="language-yaml">sentry:
  enable: true
  dsn: &quot;{Sentry DSN}&quot;</code></pre>


<p>这里的 Sentry DSN 为在 Sentry 新建项目对应的 DSN, 示例: <code>http://e85eaaa599c44cbbb6833c22c20bbbb@sentry.xx.com/123</code></p>
<hr />
<h2 id="4">4. 故障点</h2>
<p>由于 IAM 作为基础服务, 被众多上层的平台及 SaaS 依赖; 所以一旦 IAM 出现故障, 将导致其他平台大规模不可用.</p>
<p>所以使用高可用部署方案的同时, 需要了解 IAM 所有的故障点</p>
<p>目前 IAM 强依赖:</p>
<ul>
<li>数据库</li>
<li>Redis</li>
</ul>
<p>鉴权依赖:</p>
<ul>
<li>跨系统资源依赖</li>
</ul>
<h3 id="41">4.1 数据库故障</h3>
<p>如果 iam 依赖的数据库出现故障, 服务不可用, 将会导致 iam 本身服务不可用(无法提供鉴权请求);</p>
<p><strong>影响</strong>:
- 依赖数据库: <code>bkiam</code>, 建议使用<strong>主从部署</strong>确保高可用, 一旦出问题, 优先确保 DB 查询正常, 确保鉴权服务正常
- 依赖数据库: <code>open_paas</code>, 用于对应用发起请求合法性鉴权(缓存 12 小时, 所以如果 open_paas 数据库不可用, 那么短时间内, 之前正常请求的合法性鉴权不会受到影响)</p>
<p><strong>紧急预案</strong>:</p>
<ul>
<li>如果对应的 MySQL 服务短时间内无法恢复, 为了保证所有鉴权服务可用, 那么可以切换到冷备服务器, 或者紧急将<code>备份数据</code>导入到某个 MySQL 实例, 将权限中心依赖切过去</li>
<li>将<code>备份数据</code>导入</li>
<li>修改配置文件中 MySQL 配置</li>
<li>重启服务, 确认服务正常</li>
<li>待生产环境 MySQL 服务恢复后, 再切换回去</li>
<li>注意:<ul>
<li>期间写入的数据会丢失, 例如配置的新权限等</li>
<li>由于冷备服务或者备份数据的<code>权限数据</code>可能不是最新的, 可能导致部分鉴权结果差异; 差异多少取决于临时服务数据同生产环境数据差异有多大</li>
<li>建议: 建议此时周知使用者, 不使用权限中心 SaaS 配置权限/审批权限等等</li>
</ul>
</li>
</ul>
<h3 id="42-redis">4.2 Redis 故障</h3>
<p>如果 Redis 不可用, 将导致 IAM 无法使用缓存服务, 不影响鉴权的正确性, 但是影响整体服务的性能(无缓存请求会查询 db)</p>
<p><strong>影响</strong>:</p>
<ul>
<li>不影响鉴权的正确性(IAM 无法使用缓存服务, 会查询 db)</li>
<li>接口响应慢</li>
<li>如果请求量很大, 可能给 db 带来很大的压力, 最终导致 db 负载过大</li>
</ul>
<p><strong>紧急预案</strong>:</p>
<ul>
<li>
<p>[预案 1] IAM 本身启动时会检查配置 Redis 服务可用(如果此时 redis 服务不可用, 进程将拉起失败). 如果短时间内无法恢复 Redis 服务, 可以将配置文件中<code>debug: false</code>改成<code>debug: true</code>, 进程拉起</p>
<ul>
<li>注意: 此时服务可用, 无缓存, 对 db 压力会比较大</li>
</ul>
</li>
<li>
<p>[预案 2] 如果原先的生产 Redis 服务不可用, 可以配置一个临时的 Redis 服务先顶着(纯缓存, 不需要做数据持久化及备份) </p>
<ul>
<li>修改配置文件中 Redis 配置</li>
<li>重启服务, 确认服务正常</li>
<li>待生产 Redis 服务恢复后, 再切换回去</li>
<li>注意, 所有实例配置同一个临时 Redis!(确保缓存数据一致性); 并且, 必须隔离(不能同其他环境, 例如测试环境的 IAM 共用一个 Redis db);</li>
</ul>
</li>
</ul>
<h3 id="43">4.3 跨系统资源依赖的被依赖方故障</h3>
<p>跨系统资源依赖, 典型场景是 <code>Job执行作业A的权限依赖于CMDB的某个主机资源</code>, 在 IAM 鉴权时, 会到<code>被依赖方</code> CMDB 查询对应的主机资源信息</p>
<p><strong>影响</strong>:</p>
<ul>
<li>如果此时 CMDB 服务不可用(无法查询主机资源), 将导致 JOB 此类的鉴权请求全部报错</li>
</ul>
<p><strong>建议</strong>:</p>
<ul>
<li>需要监控: cmdb 整体服务可用</li>
</ul>
<p><strong>紧急预案</strong>:
- 无, 必须恢复被依赖方的服务</p>
<h3 id="44-iam">4.4 IAM 所在服务器磁盘空间满</h3>
<p><strong>影响</strong>:
- 磁盘空间写满会导致服务日志无法落地, 进而影响服务可用性</p>
<p><strong>建议</strong>:
- 需要监控 IAM 部署所在服务器的磁盘空间</p><h1 id="_1">升级部署说明</h1>
<h2 id="_2">背景</h2>
<p>文档主要说明 IAM 某些版本做了较大的变更, 导致升级前需要执行的一些特殊步骤, 以便数据等可以平滑迁移</p>
<h2 id="v3-saas-lt136-gt-14x">权限中心 V3 SaaS 从 <code>&lt;1.3.6</code> 升级到 <code>&gt;= 1.4.x</code></h2>
<blockquote>
<p>权限中心 <code>1.4.x</code> 相对于之前版本, 对用户组/权限模板做了较大修改
所以升级前, 需要升级到<code>1.3.6</code>使用这个版本提供的命令进行权限模板的数据同步</p>
</blockquote>
<p>说明:
- 如果全新部署, 不需要关注本文档, 直接安装最新版本的 SaaS 及后台
- 当前环境 SaaS 版本<code>&lt;1.3.6</code>的, 需要关注, 按步骤处理</p>
<h3 id="1">1. 升级步骤</h3>
<ol>
<li>
<p>将权限中心后台版本升级到<code>1.6.1</code>, SaaS 版本升级到<code>1.3.6</code></p>
</li>
<li>
<p>全量同步所有的权限模板</p>
</li>
</ol>
<pre class="codehilite"><code class="language-bash">ssh $BK_APPO_IP
docker exec -it $(docker ps | grep -w bk_iam | awk '{print $1}') bash
export BK_FILE_PATH=&quot;/data/app/code/conf/saas_priv.txt&quot;
/cache/.bk/env/bin/python /data/app/code/manage.py sync_templates
# 脚本打印 Successful completion of template version synchronization 表示执行同步成功</code></pre>


<ol>
<li>升级 IAM 后台到 <code>1.7.x</code>或最新版本</li>
</ol>
<pre class="codehilite"><code class="language-bash"># 检查IAM后台版本 
curl http://{IAM_HOST}/version 确认版本号</code></pre>


<p>注意, 这里的<code>{IAM_HOST}</code>是权限中心后台地址, 对应企业版社区版地址<code>curl http://bkiam.service.consul:5001/version</code>(如不确定, 具体咨询环境运维人员)
4. 升级 IAM SaaS 到 <code>1.4.x</code>或最新版本</p>
<h3 id="2">2. 异常处理</h3>
<ol>
<li>SaaS 升级到 1.4.x 报错 <code>you must sync all templates before run migrate</code></li>
</ol>
<p>请先回退 SaaS 到 1.3.6 版本, 后台 1.6.1 版本, 重新执行升级步骤后再升级 SaaS 到 1.4.x</p>
<ol>
<li>SaaS 执行 <code>python manage.py sync_templates</code> 报错 <code>ErrorCode 1902000:(code: None, message: request iam api error</code></li>
</ol>
<p>请先回退 IAM 后台到 1.6.1 版本, 再执行以上命令</p><h1 id="_1">开发测试环境搭建</h1>
<p>接入系统在正式接入权限中心前，会在开发者本地环境进行开发及联调；</p>
<p>此时，<code>切勿直接使用生产环境的IAM</code>进行对接；</p>
<p>应该:</p>
<ol>
<li>搭建一套独立的<code>开发测试环境</code>，同<code>生产环境</code>隔离；</li>
<li>这套环境需要同<code>生产环境</code>版本一致，包含<code>PaaS/ESB/用户管理/权限中心SaaS /权限中心后台</code>等</li>
<li>开发者可以通过地址访问这套环境的<code>权限中心SaaS</code>及<code>权限中心后台</code>； 通过<code>权限中心SaaS</code>配置权限，通过<code>权限中心后台</code>接口进行鉴权等</li>
<li>这套环境只用于<code>开发测试</code>，所有数据随时可以清空重建；</li>
</ol>
<h2 id="_2">本地开发步骤</h2>
<ol>
<li>阅读文档，理解权限中心相关概念/接口/协议等</li>
<li>确认<code>开发测试环境</code>的 paas 地址/iam 后台访问地址/iam saas 地址等</li>
<li>分析系统权限模型，梳理好权限模型后，可以直接使用 <a href="../Solutions/Migration.md">模型自动初始化及更新 migration</a> 脚本导入<code>开发测试环境</code></li>
<li>此时可以到<code>权限中心SaaS</code>申请及配置相关权限</li>
<li>调用接口，进行鉴权测试</li>
<li>可以阅读相关 sdk 文档，使用 sdk 进行接入 <a href="../../Reference/SDK/01-PythonSDK.md">Python SDK</a></li>
</ol><h1 id="_1">运维问题</h1>
<h1 id="1">1. 权限中心服务是否可用</h1>
<p>权限中心分为 SaaS 和 后台两部分；
- 通过桌面/控制台权限中心入口打开页面， 请求落到 SaaS， 主要处理权限申请/审批/管理等。 如果 SaaS 不可用， 需要从开发者中心查询相关日志(<code>开发者中心-Smart应用-权限中心V3-日志查询</code>)
- 接入系统鉴权等接口， 请求落到后台。如果后台不可用， 需要从 bkiam 后台日志排查对应问题(注意可能部署在多台机器)</p>
<p>如何确认权限中心 SaaS 服务可用
1. 确认 SaaS 服务健康 <code>curl -vv http://{PAAS_HOST}/o/bk_iam/healthz</code>, 正常应该返回<code>ok</code>
2. 查看 SaaS 服务的系统日志 <code>bk_iam.log</code>和 API 请求日志<code>uwsgi.log</code> 中 是否有异常堆栈信息(error)
3. 确认第三方服务是否正常, 查看<code>component.log</code>确认是否有异常信息(error)
4. 确认后台异步任务是否正常，查看<code>celery.log</code> 确认是否有异常信息(error)
5. 确认 SaaS 服务的依赖<code>MySQL</code>/<code>Redis</code>/<code>RabbitMQ</code> 可达/正常</p>
<p>如何确认权限中心后台服务可用?
1. 确认后台服务可达 <code>curl -vv http://{IAM_HOST}/ping</code>, 正常应该返回<code>{"message": "pong"}</code>(可以使用<a href="../FAQ/Debug/SelfHelp/DebugCLI.md">IAM-Debug CLI</a>确认)
2. 确认后台服务健康 <code>curl -vv http://{IAM_HOST}/healthz</code>, 正常应该返回<code>ok</code>(可以使用<a href="../FAQ/Debug/SelfHelp/DebugCLI.md">IAM-Debug CLI</a>确认)
3. 查看后台服务的系统日志 <code>iam.log</code> 是否有异常堆栈信息(error) / <code>iam_api.log</code> 中的请求处理响应时间是否超过 100ms
4. 确认后台服务所在机器的 <code>负载/网络/IO</code> 等正常
5. 确认后台服务依赖的 <code>Redis</code>/<code>MySQL</code> 可达/正常; 查看后台日志 <code>iam_sql.log</code>是否有大量 SQL 慢请求日志
6. 确认第三方服务是否正常, 查看<code>iam_component.log</code>确认是否有异常信息(error)</p><h1 id="_1">概念解释</h1>
<h2 id="system">系统(System)</h2>
<blockquote>
<p>接入权限中心的 SaaS 或平台或第三方系统</p>
</blockquote>
<p>注意, 系统跟<code>app_code</code>不是一个概念, 一个系统可能有多个子模块(多个<code>app_code</code>), 但是其共用的一套权限模型及数据, 此时只需要注册一个系统, 多个<code>app_code</code>成为这个系统合法的<code>clients</code>即可.</p>
<p>相关链接:
- <a href="../Explanation/05-AppcodeAndSystemID.md">说明: AppCode 和 SystemID</a>
- <a href="../Reference/API/02-Model/10-System.md">模型注册 API: 系统</a></p>
<h2 id="action">操作(Action)</h2>
<blockquote>
<p>权限操作，比如增删改查</p>
</blockquote>
<p>接入系统中需要做权限控制的某个场景功能，如作业新建、主机转移、菜单查看等，一个操作最好是最小原子功能，操作应该是可枚举相对静态的，一个系统的操作数量有可能随着系统功能模块的增加而增加，但一般不会随着时间的推移无限增长。</p>
<p>相关链接:
- <a href="../Reference/API/02-Model/13-Action.md">模型注册 API: 操作</a></p>
<h2 id="resourcetype">资源类型(ResourceType)</h2>
<blockquote>
<p>操作对象的资源类别</p>
</blockquote>
<p>指各系统需要做权限控制的操作所关联的对象，如作业新建关联的对象是作业、主机转移关联的对象是主机等，作业、主机都是一种资源类型。</p>
<p>相关链接:
- <a href="../Reference/API/02-Model/11-ResourceType.md">模型注册 API: 资源类型</a>
- <a href="../Reference/API/03-Callback/01-API.md">资源反向拉取 API</a></p>
<h2 id="instanceselection">实例视图(InstanceSelection)</h2>
<blockquote>
<p>实例视图, 决定了在配置权限的时候, 如何选到对应的实例</p>
</blockquote>
<p>接入系统可以根据自己的业务场景，向权限中心自定义注册多种实例视图，一种实例视图代表了一种实例的选择方式，用户在申请权限关联资源实例时，可以切换不同的 实例视图 来选择实例权限。</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/01_instance_selection_03.png" /></p>
<p>相关链接:
- <a href="../Reference/API/02-Model/12-InstanceSelection.md">模型注册 API: 实例视图</a>
- <a href="../Explanation/01-InstanceSelection.md">说明: 实例视图</a>
- <a href="../HowTo/Examples/03-Topology.md">样例 3: 使用拓扑层级管理权限</a></p>
<h2 id="_2">资源实例</h2>
<p>资源实例是某种资源类型的具体实例化对象，也是权限控制的最小粒度，如具体某个作业、某台主机等，一般来说资源实例是动态的，会随着时间推移线性增长。</p>
<p>相关链接:
- <a href="../HowTo/Examples/02-ActionWithResource.md">样例 2: 关联简单实例权限</a>
- <a href="../Explanation/06-LargeScaleInstances.md">大规模实例级权限限制</a></p>
<h2 id="_3">资源属性</h2>
<p>资源属性 是权限中心筛选资源实例的一种方式，满足那些需要动态授权的场景。</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/04_01.jpg" /></p>
<p>相关链接:
- <a href="../HowTo/Examples/04-Attribute.md">样例 4: 使用属性管理权限</a></p>
<h2 id="_4">操作组</h2>
<p>操作组是接入系统，根据系统使用习惯，将相同场景的操作按操作组归类，方便用户/管理员在权限中心勾选操作权限。 操作组只是前端勾选操作时的体验优化，不涉及底层逻辑的依赖。</p>
<p>比如，作业平台有作业执行、作业删除、脚本执行、脚本查看、IP 白名单新建、全局设置管理几个操作。</p>
<p>加上操作组后，前端表现为：</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/HowTo/Examples/05_01.jpg" /></p>
<p>相关链接:
- <a href="../Reference/API/02-Model/14-ActionGroup.md">模型注册 API: 操作组</a>
- <a href="../HowTo/Examples/05-ActionGroup.md">样例 5: 配置操作组优化权限申请</a></p>
<h2 id="_5">常用操作</h2>
<p><img alt="" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/08_common_action.jpg" /></p>
<p>相关链接:
- <a href="../Reference/API/02-Model/17-CommonActions.md">模型注册 API: 常用操作</a>
- <a href="../HowTo/Examples/06-CommonActions.md">样例 6: 配置常用操作优化权限申请</a></p>
<h2 id="_6">依赖操作</h2>
<p>当用户申请的操作权限必须依赖其他某些前置操作权限时，比如用户申请<code>项目编辑</code>，必须依赖<code>项目查看</code>的操作权限，<code>项目查看</code>就是<code>项目编辑</code>的依赖操作，用户不需要关心依赖操作，权限中心会自动处理依赖逻辑，用户直奔目标选择需要的权限即可。</p>
<p>下面的图示中, 勾选<code>项目编辑</code>会自动勾选<code>项目查看</code></p>
<p><img alt="" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/08_related_action.jpg" /></p>
<p>相关链接:
- <a href="../HowTo/Examples/07-RelatedActions.md">样例 7: 配置依赖操作优化权限申请</a></p>
<h2 id="_7">用户组</h2>
<p>用户组是权限中心推荐的权限管理方式，一个用户组可以关联多个系统的多个权限模板，从而具备对应的权限，管理员只需要往用户组添加用户/组织即可让对应的用户获得用户组的所具备的权限。</p>
<h2 id="_8">分级管理员</h2>
<p>分级管理员是权限中心的二级权限管理员，成为分级管理员后可以分配相应的资源权限给其他用户。</p><h1 id="_1">实例视图</h1>
<blockquote>
<p>本文重点阐述实例视图的概念, 示例, 在授权及鉴权阶段的作用, 帮助开发者更好地理解实例视图</p>
</blockquote>
<h2 id="1">1. 前置阅读</h2>
<ul>
<li><a href="../Reference/API/02-Model/00-Concepts.md">名词及概念</a> 中的 <code>3. InstanceSelection: 实例视图</code> 和 <code>4. Action: 权限操作，比如增删改查</code></li>
<li><a href="../Reference/API/02-Model/12-InstanceSelection.md">实例视图 InstanceSelection API</a></li>
<li><a href="../Reference/API/02-Model/13-Action.md">操作 Action API</a></li>
<li><a href="../Reference/API/03-Callback/01-API.md">资源拉取 API</a></li>
<li><a href="../Explanation/04-BkIAMPath.md">说明: 资源拓扑<code>_bk_iam_path_</code></a></li>
</ul>
<h2 id="2">2. 什么是实例视图</h2>
<blockquote>
<p>实例视图, 决定了在配置权限的时候, 如何选到对应的实例</p>
</blockquote>
<p>接入系统可以根据自己的业务场景，向权限中心自定义注册多种实例视图，<code>一种实例视图代表了一种实例的选择方式</code>，用户在申请权限关联资源实例时，可以切换不同的 <code>实例视图</code> 来选择实例, 配置对应的权限。</p>
<ul>
<li>可以勾选到具体实例</li>
<li>如果实例视图存在多级拓扑, 可以勾选上级任意节点</li>
</ul>
<h2 id="3">3. 示例</h2>
<h3 id="31">3.1 操作不关联任何示例</h3>
<p>即 <code>action</code> 的 <code>related_resource_types</code>为空; 此时配置权限时不需要选择实例, <strong>不需要配置实例视图</strong></p>
<h3 id="32">3.2 操作关联了类型实例, 实例视图是单层的</h3>
<p>以 PaaS 的开发应用为例
- <code>action=develop_app</code>
- 关联资源类型 resource_type 为<code>system_id=bk_paas; id=app</code>
- 在配置权限的时候, 这个 app 的选择是通过实例视图 instance_selection 为 <code>system_id=bk_paas, id=app_view</code>选择出来的;
- <code>app_view</code>应用视图 只有一层 <code>system_id=bk_paas, id=app</code>, 即指向资源自己, 产品上的表现就是配置权限的时候, 是平铺的应用列表</p>
<pre class="codehilite"><code class="language-json"># action model
{
  &quot;id&quot;: &quot;develop_app&quot;,
  &quot;name&quot;: &quot;开发SaaS应用&quot;,
  &quot;name_en&quot;: &quot;develop app&quot;,
  &quot;description&quot;: &quot;一个用户是否能够开发SaaS&quot;,
  &quot;description_en&quot;: &quot;Is allowed to develop SaaS app&quot;,
  &quot;type&quot;: &quot;&quot;,
  &quot;related_resource_types&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_paas&quot;,
      &quot;id&quot;: &quot;app&quot;,
      &quot;name_alias&quot;: &quot;&quot;,
      &quot;name_alias_en&quot;: &quot;&quot;,
      &quot;related_instance_selections&quot;: [
        {
          &quot;system_id&quot;: &quot;bk_paas&quot;,
          &quot;id&quot;: &quot;app_view&quot;
        }
      ]
    }
  ],
  &quot;version&quot;: 1
}

# instance selection model
{
  &quot;id&quot;: &quot;app_view&quot;,
  &quot;name&quot;: &quot;应用视图&quot;,
  &quot;name_en&quot;: &quot;app_view&quot;,
  &quot;resource_type_chain&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_paas&quot;,
      &quot;id&quot;: &quot;app&quot;
    }
  ]
}</code></pre>


<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/01_instance_selection_01.png" /></p>
<p>类似的示例: 操作<code>业务编辑</code>, 关联资源<code>业务</code>, 对应实例视图是<code>业务列表</code>, 拉取得到平铺的列表</p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/01_instance_selection_02.png" /></p>
<h3 id="33">3.3 操作关联了一种类型实例, 实例视图是多层的</h3>
<p>标准运维的任务查看为例
- <code>action=task_view</code>
- 关联资源类型 resource_type 为<code>system_id=bk_sops; id=task</code>
- 在配置权限的时候, 这个 task 的选择是通过实例视图 instance_selection 为 <code>system_id=bk_sops, id=task</code>选择出来的;
- 任务实例视图有两层 <code>system_id=bk_sops, id=project</code> / <code>system_id=bk_sops, id=task</code>, 表示 <code>项目下的任务</code></p>
<pre class="codehilite"><code class="language-json"># action model
{
  &quot;id&quot;: &quot;task_view&quot;,
  &quot;name&quot;: &quot;任务查看&quot;,
  &quot;name_en&quot;: &quot;Task View&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;description_en&quot;: &quot;&quot;,
  &quot;type&quot;: &quot;view&quot;,
  &quot;related_resource_types&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;task&quot;,
      &quot;selection_mode&quot;: &quot;all&quot;,
      &quot;related_instance_selections&quot;: [
        {
          &quot;system_id&quot;: &quot;bk_sops&quot;,
          &quot;id&quot;: &quot;task&quot;
        }
      ]
    }
  ],
  &quot;version&quot;: 1
}
# instance selection model
{
  &quot;id&quot;: &quot;task&quot;,
  &quot;name&quot;: &quot;任务实例&quot;,
  &quot;name_en&quot;: &quot;Task&quot;,
  &quot;resource_type_chain&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;project&quot;
    },
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;task&quot;
    }
  ]
}</code></pre>


<p>此时配置权限的时候, 会先拉取第一层 <code>项目列表</code>, 选择某个项目 A 后, 可以展开<code>项目A下的任务列表</code></p>
<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/01_instance_selection_03.png" /></p>
<h2 id="4">4. 实例视图回调接口</h2>
<p>注册操作及实例视图之后, 在权限中心页面配置权限的时候, 会回调接入系统接口, 拉去实例视图中每一层的资源;</p>
<ul>
<li><a href="../Reference/API/03-Callback/01-API.md">资源拉取 API</a></li>
<li><a href="../Reference/API/03-Callback/12-list_instance.md">资源拉取 API: list_instances</a></li>
</ul>
<h3 id="41">4.1 只有一层的实例视图</h3>
<p>以上面 <code>开发应用</code> 为例</p>
<pre class="codehilite"><code class="language-json">POST system.provider_config.host + system.provider_config.path
{
    &quot;type&quot;: &quot;app&quot;,
    &quot;method&quot;: &quot;list_instance&quot;,
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }
}</code></pre>


<h3 id="42">4.2 存在多层的实例视图</h3>
<p>以上面 <code>任务查看</code> 为例</p>
<p>第一层项目列表</p>
<pre class="codehilite"><code class="language-json">POST system.provider_config.host + system.provider_config.path
{
    &quot;type&quot;: &quot;project&quot;,
    &quot;method&quot;: &quot;list_instance&quot;,
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }
}</code></pre>


<p>第二层项目下的任务列表</p>
<pre class="codehilite"><code class="language-json">POST system.provider_config.host + system.provider_config.path
{
    &quot;type&quot;: &quot;task&quot;,
    &quot;method&quot;: &quot;list_instance&quot;,
    &quot;filter&quot;: {
        &quot;parent&quot;: {
            &quot;type&quot;: &quot;project&quot;,
            &quot;id&quot;: &quot;blueking&quot;
        }
    },
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }
}</code></pre>


<p>即, 每次调用接入系统接口拉取下一层资源列表的时候, 会传递父级节点的类型和 id(<code>parent{type=,id=}</code>)</p>
<h2 id="5">5. 实例视图配置的权限</h2>
<h3 id="51">5.1 实例视图是单层的</h3>
<p>以上面示例中, 开发应用的实例视图为例; 示例中, 我们勾选了<code>test12</code></p>
<pre class="codehilite"><code class="language-bash">app.id in [&quot;test12&quot;]</code></pre>


<h3 id="52">5.2 实例视图是多层的</h3>
<p>以上面示例中, 任务查看的示例视图为例</p>
<p>如果勾选了 <code>项目蓝鲸下的任务test</code></p>
<pre class="codehilite"><code class="language-bash">task.id eq test
AND
task._bk_iam_path_ starts_with /project,蓝鲸ProjectID/</code></pre>


<p>如果勾选了 <code>项目蓝鲸</code>, 代表项目蓝鲸下的所有任务都有权限, <strong>包括未来在项目蓝鲸下新添加的所有任务</strong></p>
<pre class="codehilite"><code class="language-bash">task._bk_iam_path_ starts_with /project,蓝鲸ProjectID/task,*/</code></pre>


<h3 id="53-ignore_iam_pathtrue">5.3 实例是多层的, 并且 ignore_iam_path=true</h3>
<p>以上面任务查看为例, 如果在配置操作的实例视图时, 配置了<code>ignore_iam_path=true</code></p>
<pre class="codehilite"><code class="language-json"># action model
{
  &quot;id&quot;: &quot;task_view&quot;,
  &quot;name&quot;: &quot;任务查看&quot;,
  &quot;name_en&quot;: &quot;Task View&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;description_en&quot;: &quot;&quot;,
  &quot;type&quot;: &quot;view&quot;,
  &quot;related_resource_types&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;task&quot;,
      &quot;selection_mode&quot;: &quot;all&quot;,
      &quot;related_instance_selections&quot;: [
        {
          &quot;system_id&quot;: &quot;bk_sops&quot;,
          &quot;id&quot;: &quot;task&quot;,
          &quot;ignore_iam_path&quot;: true
        }
      ]
    }
  ],
  &quot;version&quot;: 1
}
# instance selection model
{
  &quot;id&quot;: &quot;task&quot;,
  &quot;name&quot;: &quot;任务实例&quot;,
  &quot;name_en&quot;: &quot;Task&quot;,
  &quot;resource_type_chain&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;project&quot;
    },
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;task&quot;
    }
  ]
}</code></pre>


<p>如果勾选了 项目蓝鲸下的 test</p>
<pre class="codehilite"><code class="language-bash">task.id == test123</code></pre>


<p>如果勾选了 <code>项目蓝鲸</code>, 代表项目蓝鲸下的所有任务都有权限</p>
<pre class="codehilite"><code class="language-bash">task._bk_iam_path_ starts_with /project,蓝鲸ProjectID/task,*/</code></pre>


<p>注意, <code>ignore_iam_path</code> <strong>只对叶子节点生效</strong>, 对勾选中间节点的场景不起作用;</p>
<h2 id="6">6. 实例视图配置的鉴权</h2>
<p>如果实例视图是多层的, 那么对应资源在进行鉴权的时候, 资源必须带上属性<code>_bk_iam_path_</code>, 且如果操作配置了多种实例视图, 那么<code>_bk_iam_path_</code>需要带上所有实例视图下的链路信息; 否则鉴权可能会有问题;</p>
<p>例如, 主机查看配置了两个实例视图</p>
<ul>
<li><code>集群 - 主机</code></li>
<li><code>模块 - 主机</code></li>
</ul>
<p>那么用户在配置权限的时候, 可能用任意一个实例视图配置出权限, 也可能两个实例视图都使用; 即, 策略里面可能保存了两条链路下的策略;</p>
<p>所以, 鉴权的时候, <code>主机</code> 的<code>_bk_iam_path_</code>需要提供两个视图下的链路, 以确保鉴权正确;</p>
<pre class="codehilite"><code class="language-json">{
    &quot;system&quot;: &quot;bk_cmdb&quot;,
    &quot;type&quot;: &quot;host&quot;,
    &quot;id&quot;: &quot;192.168.1.1&quot;,
    &quot;attribute&quot;: {
        &quot;_bk_iam_path_&quot;: [
            &quot;/cluster,c1/&quot;,  
            &quot;/module, m1/&quot;  
        ]
    }
}</code></pre>


<p>具体见 <a href="../Explanation/04-BkIAMPath.md">说明: 资源拓扑<code>_bk_iam_path_</code></a></p>
<h2 id="7">7. 什么时候需要多层实例视图</h2>
<p>资源本身存在业务上的<code>拓扑</code>关系, 例如, 选取某一台主机, 可以是<code>业务A 下的 集群B 下的 模块C 下的主机</code></p>
<p>例如<code>编辑主机</code>操作, 关联的资源类型是<code>主机</code>, 主机对应的实例视图是<code>主机视图</code>;  对应可以配置出来的权限是</p>
<ul>
<li><code>业务A</code> 下的所有主机</li>
<li><code>业务A / 集群B</code> 下的所有主机</li>
<li><code>业务A / 集群B / 模块C</code> 下的所有主机</li>
<li><code>业务A / 集群B / 模块C</code> 下的主机 A (<code>ignore_iam_path=false</code>)</li>
<li>主机 A (<code>ignore_iam_path=true</code>)</li>
</ul><h1 id="_1">权限模型</h1>
<blockquote>
<p>本文重点阐述常见的权限模型, 方便大家理解和接入权限中心</p>
</blockquote>
<h2 id="aclaccess-control-list">ACL(Access Control List) 访问控制表</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Access-control_list">wiki: ACL</a></li>
<li>最简单的权限模型;</li>
</ul>
<p><img alt="" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/02_acl.jpg" /></p>
<p>示例: 小明有 仓库 1 的 commit 权限
- 策略数据: <code>小明, 仓库1, commit</code>
- 结果: 小李没有仓库 1 的提交权限</p>
<h2 id="rbacrole-base-access-control">RBAC(Role Base Access Control) 基于角色的访问控制</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Role-based_access_control">wiki: RBAC</a></li>
<li>最常见的权限模型</li>
</ul>
<p><img alt="" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/02_rbac.jpg" /></p>
<p>示例: 管理员有仓库 1 的 commit 权限
- 策略数据: <code>admin, 仓库1, commit</code>
- 小明是管理员 <code>小明, admin</code>
- 小李不是管理员
- 结果: 小明有仓库 1 的提交权限, 小李没有仓库 1 的提交权限</p>
<h2 id="abacattribute-base-access-control">ABAC(Attribute Base Access Control) 基于属性的访问控制</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Attribute-based_access_control">wiki: ABAC</a></li>
<li>最强大灵活的权限模型</li>
</ul>
<p><img alt="" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/02_abac.jpg" /></p>
<p>示例: <code>管理员有 公开仓库的 提交权限</code>
- 策略数据: <code>subject.role=admin, repo.type=public, action=commit</code>
- 小明是管理员(subject.role=admin), 小李不是管理员
- 仓库 1 是公开的(repo.type=public), 仓库 2 是私有的(repo.type=private)
- 结果: 小明有仓库 1 的提交权限, 没有仓库 2 的提交权限; 小李没有仓库 1 的提交权限, 也没有仓库 2 的提交权限</p>
<h2 id="_2">三种模型的简单对比</h2>
<table>
<thead>
<tr>
<th></th>
<th>ACL</th>
<th>RBAC</th>
<th>ABAC</th>
</tr>
</thead>
<tbody>
<tr>
<td>全称</td>
<td>Access Control List</td>
<td>Role Base Access Control</td>
<td>Attribute Base Access Control</td>
</tr>
<tr>
<td>模型</td>
<td>用户 - 资源 - 操作</td>
<td>用户 - 角色 - 资源 - 操作</td>
<td>用户/属性 - 资源/属性 - 操作/属性 - 环境属性</td>
</tr>
<tr>
<td>优点</td>
<td>简单</td>
<td>简单/管理方便</td>
<td>动态灵活</td>
</tr>
<tr>
<td>问题</td>
<td>策略多时难以管理</td>
<td>Role explosions</td>
<td>实现复杂</td>
</tr>
<tr>
<td>适用场景</td>
<td>小型系统(组织架构)</td>
<td>中小型系统(组织架构)</td>
<td>大型系统/大型组织</td>
</tr>
</tbody>
</table>
<p>ABAC 是包含 ACL 及 RBAC 的</p>
<ul>
<li>ACL = 用户 - 资源 - 操作</li>
<li>RBAC = 用户属性(角色) - 资源 - 操作</li>
</ul>
<h2 id="_3">蓝鲸权限中心使用的模型</h2>
<p>权限中心将支持完备的 ABAC 模型, 目前根据需求及优先级, 策略表达式 v1 版本优先支持了资源属性</p>
<h3 id="policy-v1">policy v1(已发布)</h3>
<blockquote>
<p>支持资源属性</p>
</blockquote>
<p><img alt="" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/02_policy_v1.jpg" /></p>
<ul>
<li>Subject: id/type</li>
<li>Resource: id/type/attribute</li>
<li>Action: id</li>
<li>Environment: -</li>
</ul>
<h3 id="policy-v2">policy v2(开发中)</h3>
<blockquote>
<p>支持用户属性</p>
</blockquote>
<p><img alt="" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/02_policy_v2.jpg" /></p>
<ul>
<li>Subject: id/type/attribute</li>
<li>Resource: id/type/attribute</li>
<li>Action: id</li>
<li>Environment: -</li>
</ul>
<h3 id="policy-v3">policy v3(规划中)</h3>
<blockquote>
<p>支持环境属性</p>
</blockquote>
<p><img alt="" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/02_policy_v3.jpg" /></p>
<ul>
<li>Subject: id/type/attribute</li>
<li>Resource: id/type/attribute</li>
<li>Action: id</li>
<li>Environment: attribute</li>
</ul><h1 id="_1">权限模型注册的几种方式</h1>
<blockquote>
<p>本文重点阐述开发者构建好权限模型之后, 如何将权限模型注册到权限中心</p>
</blockquote>
<p>开发者可以根据权限中心的文档, 构建好权限模型; 或者通过<code>页面接入</code>功能, 在表单中填写后导出权限模型数据.</p>
<h2 id="1-api">1. 使用模型注册 API 注册</h2>
<p>使用模型注册 API, 直接将权限模型注册到权限中心;</p>
<ul>
<li><a href="../Reference/API/02-Model/00-API.md">模型注册 API</a></li>
<li>示例 <a href="../QuickStart/03-Model.md">QuickStart: 模型注册</a></li>
</ul>
<p>适用:
- 非 python(Django)开发的系统
- 权限模型变更不频繁的系统
- 中大型系统, 可以通过代码及模型配置, 自己完成初始化(需要自行确保注册顺序)</p>
<h2 id="2-do_migratepy">2. 使用 do_migrate.py</h2>
<p>将模型数据转化成 json 文件, 使用脚本进行模型注册; 推荐操作代码<code>operation</code>使用<code>upsert_XXX</code></p>
<ul>
<li><a href="../HowTo/Solutions/Migration.md">权限模型自动初始化及更新 migration</a></li>
</ul>
<p>适用:
- 模型变更频繁的系统
- 不想开发及维护模型注册代码/配置, 通过 json 完成模型数据注册及更新(json 文件及每个操作位置, 决定了最终注册顺序)</p>
<h2 id="3-django-migration">3. 使用 Django migration</h2>
<p>如果开发者使用 Django 开发的系统, 那么可以利用<a href="https://github.com/TencentBlueKing/iam-python-sdk">iam-python-sdk</a>提供的 <code>IAM Migration</code>, 将模型注册集成到<code>Django Migration</code>中</p>
<ul>
<li><a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/docs/usage.md#2-iam-migration">iam-python-sdk: iam migration</a></li>
</ul>
<p>适用:
- 使用 Django 开发的系统</p><h1 id="_bk_iam_path_">资源拓扑<code>_bk_iam_path_</code>说明</h1>
<blockquote>
<p>本文重点阐述<code>_bk_iam_path_</code>的概念及开发者如何配置及使用</p>
</blockquote>
<h2 id="_1">背景</h2>
<p>如果系统使用<code>拓扑层级</code>来管理权限, 就会涉及到<code>实例视图</code>(拓扑层级意味着实例视图是多层的)</p>
<p>此时, 
1. 在鉴权等请求权限中心的接口中, 需要构造并传递资源的<code>_bk_iam_path_</code>
2. 用户在权限中心页面配置权限的时候, 权限中心会回调接入系统的接口请求资源信息, 实例接口需要返回实例的<code>_bk_iam_path_</code></p>
<p><strong>注意: 如果操作配置了实例视图, 并且实例视图是多层的, 那么必须构造并传递<code>_bk_iam_path_</code></strong></p>
<p>相关文档: 
* <a href="./01-InstanceSelection.md">说明: 实例视图</a>
* <a href="../HowTo/Examples/03-Topology.md">样例 3: 使用拓扑层级管理权限</a>
* <a href="../Reference/API/03-Callback/01-API.md">资源反向拉取 API</a></p>
<h2 id="_bk_iam_path__1"><code>_bk_iam_path_</code>是什么</h2>
<p><code>_bk_iam_path_</code>是权限中心对<code>拓扑路径</code>的一种表达形式; </p>
<p>相当于一个资源实例的拓扑</p>
<p>如果一台主机<code>192.168.1.1</code>
- 属于<code>业务 A 下的集群 B 下的主机</code>, 那么此时其<code>_bk_iam_path_=["/biz,A/cluster,B/"]</code>; 
- 如果这个机器又同时属于集群 C, 那么其<code>_bk_iam_path_=["/biz,A/cluster,B/", "/biz,A/cluster,C/"]</code></p>
<h2 id="_2">格式及内容</h2>
<ul>
<li>key: <code>_bk_iam_path_</code></li>
<li>value: <code>["/ParentType1,parentType1InstancA/ParentType2,parentType2InstanceB/", ...]</code></li>
</ul>
<h2 id="_3">示例</h2>
<p>标准运维的任务查看为例
- 操作: <code>任务查看</code>(<code>action=task_view</code>)
- 关联资源类型 resource_type 为 <code>任务</code>(<code>system_id=bk_sops; id=task</code>)
- 在配置权限的时候, 这个 task 的选择是通过实例视图 instance_selection 为 <code>任务实例视图</code>(<code>system_id=bk_sops, id=task</code>) 选择出来的;
- 任务实例视图(<code>system_id=bk_sops, id=task</code>) 有两层:  <code>system_id=bk_sops, id=project</code> / <code>system_id=bk_sops, id=task</code>, 表示 <code>项目下的任务</code></p>
<pre class="codehilite"><code class="language-json"># action model
{
  &quot;id&quot;: &quot;task_view&quot;,
  &quot;name&quot;: &quot;任务查看&quot;,
  &quot;name_en&quot;: &quot;Task View&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;description_en&quot;: &quot;&quot;,
  &quot;type&quot;: &quot;view&quot;,
  &quot;related_resource_types&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;task&quot;,
      &quot;selection_mode&quot;: &quot;all&quot;,
      &quot;related_instance_selections&quot;: [
        {
          &quot;system_id&quot;: &quot;bk_sops&quot;,
          &quot;id&quot;: &quot;task&quot;
        }
      ]
    }
  ],
  &quot;version&quot;: 1
}
# instance selection model
{
  &quot;id&quot;: &quot;task&quot;,
  &quot;name&quot;: &quot;任务实例&quot;,
  &quot;name_en&quot;: &quot;Task&quot;,
  &quot;resource_type_chain&quot;: [
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;project&quot;
    },
    {
      &quot;system_id&quot;: &quot;bk_sops&quot;,
      &quot;id&quot;: &quot;task&quot;
    }
  ]
}</code></pre>


<p><img alt="-w2021" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Explanation/01_instance_selection_03.png" /></p>
<p>如果勾选了 <code>项目蓝鲸下的任务test</code></p>
<pre class="codehilite"><code class="language-bash">task.id eq test
AND
task._bk_iam_path_ starts_with /project,蓝鲸ProjectID/</code></pre>


<p>如果勾选了 <code>项目蓝鲸</code>, 代表项目蓝鲸下的所有任务都有权限, <strong>包括未来在项目蓝鲸下新添加的所有任务</strong></p>
<pre class="codehilite"><code class="language-bash">task._bk_iam_path_ starts_with /project,蓝鲸ProjectID/task,*/</code></pre>


<h2 id="_4">鉴权</h2>
<p>鉴权传递的资源, 是<code>操作</code>关联对应的资源; 此时需要注意, 由于关联了实例视图, 使用拓扑来管理权限, 所以, 在鉴权的时候需要构造并传递<code>_bk_iam_path_</code></p>
<p><strong>注意: 如果操作配置了实例视图, 并且实例视图是多层的, 那么必须构造并传递<code>_bk_iam_path_</code></strong></p>
<p><code>_bk_iam_path_</code>的值即当前实例的拓扑链路</p>
<p>上面的示例中, 实例视图是<code>project下的task</code>, 所以鉴权<code>view_task</code>的时候, 传递<code>task</code>实例需要的<code>_bk_iam_path_=/project,对应的project/</code>; </p>
<p>如果操作配置了多个实例视图, 需要传递对应的<code>_bk_iam_path_</code>, 因为用户可能用任意一个视图申请权限; 如果少传递了, 对应的策略不会被命中, 会导致无权限.</p>
<h3 id="1-sdk">1. SDK 鉴权</h3>
<ul>
<li><a href="../Reference/API/04-Auth/01-SDK.md">SDK 鉴权</a></li>
<li><a href="../QuickStart/04-Auth.md">QuickStart: 鉴权</a></li>
</ul>
<pre class="codehilite"><code class="language-python">from iam import IAM, Request, Subject, Action, Resource


SYSTEM_ID = &quot;bk_sops&quot;
APP_CODE = &quot;&quot;
APP_SECRET = &quot;&quot;
BK_IAM_HOST = &quot;http://{IAM_HOST}&quot;
BK_PAAS_HOST = ''


class Permission(object):
    def __init__(self):
        self._iam = IAM(APP_CODE, APP_SECRET, BK_IAM_HOST, BK_PAAS_HOST)

    def _make_request_with_resources(self, username, action_id, resources):
        request = Request(
            SYSTEM_ID,
            Subject(&quot;user&quot;, username),
            Action(action_id),
            resources,
            None,
        )
        return request

    def allowed_task_view(self, username, task_id):
        &quot;&quot;&quot;
        app开发权限
        &quot;&quot;&quot;
        # get task project first, 这里假设一个task只属于一个project
        task = Task.Objects.get(id=task_id)
        project_id = task.project.id

        r = Resource(SYSTEM_ID, 'task', task_id, {
            &quot;_bk_iam_path_&quot;: [&quot;/project,%s/&quot; % project_id],
        })

        resources = [r]
        request = self._make_request_with_resources(username, &quot;task_view&quot;, resources)
        return self._iam.is_allowed(request)</code></pre>


<h3 id="2-api">2. 直接鉴权 API</h3>
<p><a href="../Reference/API/04-Auth/02-DirectAPI.md">直接鉴权 API: policy auth</a></p>
<pre class="codehilite"><code class="language-json">{
  &quot;system&quot;: &quot;bk_sops&quot;,
  &quot;subject&quot;: {
    &quot;type&quot;: &quot;user&quot;,
    &quot;id&quot;: &quot;admin&quot;
  },
  &quot;action&quot;: {
    &quot;id&quot;: &quot;task_view&quot;
  },
  &quot;resources&quot;: [
    {
      &quot;system&quot;: &quot;bk_sops&quot;,
      &quot;type&quot;: &quot;task&quot;,
      &quot;id&quot;: &quot;test&quot;,
      &quot;attribute&quot;: {
        &quot;_bk_iam_path_&quot;: [
          &quot;/project,蓝鲸ProjectID/&quot;
        ]
      }
    }
  ]
}</code></pre>


<h2 id="_5">资源反向拉取</h2>
<ul>
<li><a href="../Reference/API/03-Callback/13-fetch_instance_info.md">资源反向拉取: 4. fetch_instance_info</a></li>
</ul>
<p>资源反向拉取获取一批实例属性的时候, 可能会要求接入系统返回实例的<code>_bk_iam_path_</code>属性, 按照规范返回即可</p><h1 id="appcode-systemid">AppCode 和 SystemID</h1>
<blockquote>
<p>本文重点阐述<code>app_code</code>和<code>system_id</code>的区别及使用</p>
</blockquote>
<h2 id="1-app_code">1. app_code</h2>
<p><code>app_code</code>  代表 app 的唯一身份, <code>app_code+app_secret</code>进行的身份校验.</p>
<p><strong>唯一被使用的地方是放在 http 请求头里面做校验</strong>(不应该出现在其他地方), 具体见 <a href="../Reference/API/01-Overview/02-APIBasicInfo.md">接口协议前置说明</a></p>
<ul>
<li><code>X-Bk-App-Code</code>  蓝鲸应用 app_code</li>
<li><code>X-Bk-App-Secret</code>  蓝鲸应用 app_secret</li>
</ul>
<p>注意, app_code 可能在不同环境不一样, 例如把<code>应用1</code>部署到测试环境, app_code 可以是<code>bk_test1</code>, 部署到另一套环境, app_code 可以是<code>bk_test1_prod</code></p>
<h2 id="2-system_id">2. system_id</h2>
<p>system_id 是接入系统注册到权限中心的唯一标识; </p>
<p><strong>使用位置: 在拼接 url 地址 / http 请求 body 中</strong></p>
<h2 id="3">3. 区别</h2>
<p>理论上, <code>system_id</code> 同 <code>app_code</code> 没有关系; <strong>一定不要混用</strong></p>
<ul>
<li><code>在企业版/社区版, 限制了一个app_code只能创建一个system, 且该system的ID等于app_code</code></li>
<li>上云版, 关闭了这个限制; 所以会出现 app_code 不等于 system_id</li>
<li>其他环境, 可以控制是否开启这个限制</li>
</ul>
<p>建议: <strong>在代码逻辑中, 请同时声明 app_code 和 system_id 两个变量, 即使这两个变量的值当前是一致的!</strong></p>
<h2 id="4-app-system">4. 多个 app 共用同一套 system 的权限数据</h2>
<p>使用场景: 存在多个 app, 例如微服务体系下的多套系统, 共用的一套权限数据; 此时由一个主系统注册权限模型, 其他子系统共用权限数据; </p>
<p>此时, 多个 app_code 需要调用同一个 system_id 的接口进行策略查询/鉴权等操作</p>
<p>解决方案: system 注册的时候, 声明了<code>clients=[app_code]</code>列表, 即允许哪些 app 可以调用这个系统的权限数据; 具体文档<a href="../Reference/API/02-Model/10-System.md">系统(System) API</a></p><h1 id="_1">大规模实例级权限限制</h1>
<h2 id="_2">结论</h2>
<blockquote>
<p>接入系统需要评估现有权限模型, 对于使用<code>新建关联接口</code>和<code>实例授权接口</code>的权限管理进行 review, 合理需要确认加白名单, 不合理需要尽早变更权限模型!</p>
</blockquote>
<p><strong>规则红线</strong>: 所有产品形成共识, 定下<code>红线</code>, 要么修改权限管理为<code>范围授权</code>, 要么在确认单个人实例权限不会超过 10000 个的前提下使用现有的<code>新建关联</code>及<code>实例授权</code>; 如果都没有做而是暴力调用接口进行<code>大规模实例授权</code>, 那么<code>超过10000个之后, 接口报错, 需要接入系统自己解决(查询/合并/回收等)</code></p>
<hr />
<p>当前限制:
- <code>1个人拥有1个操作 + 1个资源类型</code>的实例权限最大数量：<code>10000</code>个。(触发后, 授权接口报错/用户无法继续增加实例权限) (<strong>当前是 10000 个, 可能会降低配额, 待定</strong>)
- 个人从无权限跳转<code>单次</code>申请数量限制：20 个（跳转过来超过 20 个，实例还是选中，点击提交按钮，提示用户超限）
- 个人 web 页面<code>单次</code>申请数量限制：20 个（超过 20 个，实例可以选中，点击提交按钮，提示用户超限）
- 个人的<code>新建关联接口</code>/<code>实例授权接口</code> 限制：20 个(<strong>当前是 200, 会发版降低为 20 个</strong>)</p>
<p>注意:
- 个人总数超 10000，接口报错提示：用户[username]的[action]操作关联的[resource_type]的实例数已达上限 10000 个，请改用范围或者属性授权。
- 单次超过限制提示：单次申请限 xx 个实例，实例权限数过多不利于您后期维护，更多实例建议您申请范围权限。</p>
<hr />
<h2 id="1">1. 背景</h2>
<p>权限中心是基于 ABAC 建立的权限体系, 目的是以最灵活的方式支持不同系统的各种权限管理场景.</p>
<p>当前, 权限中心支持<code>有限制</code>的实例授权
- 权限中心支持<code>实例级别</code>的权限管理, 可以在申请页面单独申请某些实例的权限. 例如: 单独申请某个主机的查看权限
- 申请页面最多一次批量申请<code>20</code>个实例权限
- 当前支持单个人单个操作最多<code>10000</code>个实例</p>
<p>由于各个系统的需求, 权限中心提供了<code>新建关联权限接口</code>(新建一个实例后自动拥有增删改查等权限)和<code>实例授权接口</code>(接入系统可以主动授权)</p>
<p>导致目前部分系统<code>误用</code>了这两个接口, 进行<code>大规模实例授权</code>, 导致会很快触发单个人单个操作<code>10000</code>个实例的规则. 届时, 接入系统给这个人所有授权相关操作都会报错.</p>
<p>核心矛盾:
- 设计之初, 目标就是<code>范围授权</code>, 以及<code>有限制的实例授权</code>, 不可能支持无限制的实例授权(目前限制单个人单个操作 10000 实例)
- 接入系统, 更多会直接以最简单的模型对接, 而不是评估权限模型的合理性, 导致大规模实例授权的存在!</p>
<p>本质上:
- 权限中心只支持<code>范围授权</code>, 以及<code>有限制的实例授权</code>
- 每个人超过 10000 个以上的实例权限管理放任何系统实现都是一个复杂的方案(单个资源类型的权限关系表可能十万/百万级的数据量), 而且对应系统产品上如何管理单个人的 10000 个以上实例权限也是一个问题. 所以更不应该认为现有权限中心能支持<code>无限制的实例权限</code>管理</p>
<hr />
<h2 id="2">2. 当前面临的问题</h2>
<p>接入系统在进行权限接入时, 没有进行仔细的评估, 对产品的权限模型没有进行深入的考虑, 而是以最简单直接的方式, 调用<code>新建关联接口</code>和<code>实例授权接口</code>实现业务逻辑(这样的开发成本最低, 但是会带来问题)</p>
<p>例如:
- 导入 2000 台主机, 直接遍历 2000 台主机给这个用户逐一授权;
- 一个任务模板, 每执行一次, 就生成一个实例, 将这个实例给这个用户授权; 
- 在 5000 台主机上授权脚本的可执行权限, 遍历逐一授权</p>
<p>带来的问题:
- <strong>权限无法管理</strong>, 最终这批数据变成<code>三不管</code>
    - 个人无法管理: 在<code>我的权限</code>看到<code>主机查看</code>权限的实例有 10000 台主机
    - 接入系统无法管理: 授权后, 主机变更/人员变更等等带来的变化无法同步变更对应权限
    - 权限中心无法管理: 本质上权限中心只做存储和展示, 变更由用户通过界面或接入系统通过 API 操作
- 个人策略过大
    - 策略查询给权限中心/redis/mysql 带来很大的压力, 1W 个 ID 约 100KB, 整体策略可能上<code>M</code>;
    - 网络传输数据量变大
    - 接入系统鉴权<code>慢</code>, 因为计算量变大</p>
<hr />
<h2 id="3">3. 当前新接入系统哪些触发了限制</h2>
<p><strong>具体还是需要各个产品自行评估</strong></p>
<hr />
<h2 id="4">4. 怎么解决这个问题</h2>
<blockquote>
<p>所有系统应该以<code>符合新版权限中心要求</code>的权限模型接入, 而不是沿袭原先简单粗暴的接入方式</p>
</blockquote>
<p>本质上, 希望接入系统深入思考自己产品的权限模型</p>
<p>所以, 接入系统需要评估目前调用<code>新建关联接口</code>和<code>实例授权接口</code>的合理性, 是否可能会超过 10000 个 ID</p>
<h3 id="41">4.1 如果现有的模型不合理, 需要优化为<code>范围</code>授权</h3>
<p>以<code>范围</code>来管理权限, 避免简单粗暴的实例级别授权</p>
<p>可以借助<code>拓扑</code>和<code>属性</code>来进行权限管理
- 拓扑: 某个业务下的所有主机 / 某个模块下的主机
- 属性: 主机包含属性<code>system=linux/windows</code>, 配置权限支持 有<code>system=linux</code>的所有主机查看权限;</p>
<h3 id="42">4.2 如果评估过是合理的<code>实例级别</code>权限管理</h3>
<p>可以到权限中心<code>加白名单</code>, 继续使用</p>
<p>例如:
- PaaS: 目前 app 总的数量小于 2000 个, 个人用户 app 的数量不会超过 1000
- Job: 内部版 10 年时间脚本和作业个人创建的最多 3600 个</p>
<h3 id="43">4.3 自行实现</h3>
<p><strong>不推荐, 将无法使用统一的权限管理/鉴权等. 只有某些场景适合</strong></p>
<hr />
<h2 id="5-10000">5. 超过 10000 个的后果</h2>
<p>影响范围: 个人</p>
<ul>
<li>这个人新建关联/实例授权接口报错</li>
<li>这个人新申请权限审批报错</li>
<li>这个人的鉴权可能非常慢(因为实例 ID 过多)</li>
</ul>
<p><strong>超过之后, 需要接入系统自行解决!</strong>
<strong>超过之后, 需要接入系统自行解决!</strong>
<strong>超过之后, 需要接入系统自行解决!</strong></p>
<p>所以, 请仔细评估, 尽早处理掉有问题的权限模型!!!!!!</p>
<hr />
<h2 id="6-10000">6. 如果超过 10000 限制该如何解决</h2>
<p><strong>再次声明, 接入系统需要自行解决!</strong>
如果接入系统没有仔细评估过权限模型, 导致无限制给单个用户授实例权限, 那么会有用户超过 10000 个 ID 的限制(随着时间推移, 最终会有越来越多的人超过限制)</p>
<p>解决步骤:
1. <a href="../Reference/API/08-Query/02-PolicyList.md">拉取操作的策略列表</a>
2. 接入系统自行解析表达式, 根据 id 查询本系统, 能够合并的范围, 生成新的权限(范围授权)
3. 调用授权接口授权, 将新的权限写入系统 <a href="../Reference/API/06-GrantRevoke/01-Topology.md">资源拓扑授权/回收</a>
4. 产品上废弃掉原有的 action, 使用新的 action 进行权限判断</p>
<hr />
<h2 id="7">7. 哪些场景不应该  <code>使用实例级别授权</code>  并且  <code>同步到权限中心</code></h2>
<blockquote>
<p>如果接入系统自己知道 <code>有权限</code>, 就不需要授权到权限中心
使用范围授权</p>
</blockquote>
<h3 id="71">7.1 创建者</h3>
<p>某些系统的场景, 创建者一定有权限; 例如, 应用的创建者一定有应用的增删改查权限;</p>
<ul>
<li>解决方案 1: 接入系统先判断用户是否是否创建者, 如果是, 有权限, 非创建者再到权限中心鉴权.</li>
<li>解决方案 2: 记录资源的<code>creator=tom</code> ; 使用属性授权 <code>resource.creator=tom</code>, 进行鉴权是传递 resource 的属性即可</li>
</ul>
<h3 id="72">7.2 默认权限</h3>
<p>系统有一批默认权限, 例如某个项目的管理员, 默认有项目的增删改查权限(新建一个项目后有 150 个默认权限), 这种默认权限是基于<code>角色</code>的不能变更的, 如果是<code>这个角色一定有这个权限</code></p>
<p>此时, 应该在应用层面消化掉<code>默认权限</code>; 代码层面消化默认权限, 可能只需要一个函数, 如果注册到权限中心, 那么 1W 个项目会产生 150W 条默认策略，用户根本无法有效管理。</p>
<h3 id="73">7.3 可以使用拓扑配置权限</h3>
<p>某个模块 A 下有 2000 台主机, 如果是增删改查 4 个权限, 以主机维度授权, 需要 8000 条策略</p>
<ul>
<li>解决方案: 配置模块授权,  <code>/模块,A/主机,*/</code></li>
</ul>
<h3 id="74">7.4 可以使用属性配置权限</h3>
<p>实例和实例之间是有某些共性的, 例如通过属性分类, 然后基于属性进行管理</p>
<p>例如主机有个<code>type</code>是表示其用途, 例如 <code>mysql/redis/es</code>, 可以按照 type 分类; 此时<code>数据库运维</code>管理<code>mysql</code>主机的权限, 不需要一台台授权</p>
<ul>
<li>解决方案: 配置属性授权, <code>host.type=mysql</code></li>
</ul>
<p>如果本身资源没有这类属性, 但是权限管理又需要这类属性, 那么可以</p>
<ul>
<li>解决方案: 实际使用过程中, 可以通过给资源打标签, 然后使用标签配置权限(本质上就是属性);</li>
</ul>
<h3 id="75">7.5 自己知道的权限</h3>
<p>同<code>1. 创建者</code>/<code>2. 默认权限</code>类似, 如果接入系统能够知道, 或者通过计算知道权限, 就不需要走权限中心.</p>
<p>例如: 有系统 A 对象和 B 对象, 生成 C 对象, C 对象继承 A/B 的权限; 此时 A/B/C 均是十万级的; 每个人会拥有 10W 级别的实例权限</p>
<p>错误的做法: 定时的离线计算任务, 每天计算 A/B/C 的权限, 同步刷到权限中心;</p>
<ul>
<li>解决方案: 实时计算<code>角色继承</code>关系得到权限; 或者优化模型使用<code>标签</code>/<code>属性</code>来管理权限</li>
</ul>
<h3 id="76">7.6 大规模批量导入（新建）场景</h3>
<p>接入系统如果存在大规模批量导入（新建）实例的功能，比如资源池主机、模型实例，这种很容易导入 1000 台以上的实例，而且导入后需要赋予导入者（创建者）实例其他权限（比如删改查），这种场景<code>强烈建议不要</code>做大规模实例的赋权操作。</p>
<ul>
<li>解决方案: 建议默认不赋予任何权限，去掉新建关联配置，用户需要额外的权限，可以单独申请。</li>
</ul>
<hr />
<h2 id="8">8. 对外其他系统接入(非蓝鲸体系应用)</h2>
<blockquote>
<p>权限中心是一套<code>范围授权</code>+<code>有限实例授权</code>的系统</p>
</blockquote>
<ol>
<li>无<code>新建关联接口</code>及文档</li>
<li>无<code>实例授权接口</code>及文档</li>
<li>可以<code>范围授权</code>(属性授权及拓扑授权)</li>
<li>能通过页面进行实例权限申请(单次最多 20 个)</li>
<li>对于高级用户(能深入评估权限模型, 并确认限制, 并自行承担误用超过 10000 个限制的后果)有文档支持 开通<code>新建关联</code>及<code>实例授权</code>的接口</li>
</ol><h1 id="_1">权限中心限制</h1>
<h2 id="1">1. 背景</h2>
<p>如果在调用 API 或者使用产品时, 可能会出现错误消息, 提示某些数据超过了限制, 那么可能触发了某些阈值;</p>
<p>请根据错误提示, 阅读并确认</p>
<h2 id="2">2. 限制</h2>
<h3 id="21">2.1 系统模型限制</h3>
<ul>
<li>一个 appCode 只能注册 1 个 system(限制 system_id 必须等于 app_code)</li>
<li>一个系统最多能注册 100 个操作(action)</li>
<li>一个系统最多能注册 50 个资源类型(resourceType)</li>
<li>一个系统最多能注册 50 个实例视图(instanceSelection)</li>
</ul>
<h3 id="22">2.2 产品使用限制</h3>
<table>
<thead>
<tr>
<th>限制类型</th>
<th>限制项</th>
<th>最大值</th>
<th>其他限制说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>用户</td>
<td>一个用户可加入的用户组个数</td>
<td>100</td>
<td></td>
</tr>
<tr>
<td></td>
<td>一个用户可绑定的策略中的实例个数</td>
<td>10000</td>
<td>具体见: 大规模实例级权限限制</td>
</tr>
<tr>
<td></td>
<td>一个用户可加入的分级管理员个数</td>
<td>100</td>
<td></td>
</tr>
<tr>
<td>用户组</td>
<td>一个用户组可以绑定一个系统的权限模板个数</td>
<td>10</td>
<td></td>
</tr>
<tr>
<td></td>
<td>一个用户组可添加的成员(用户或组织)个数</td>
<td>500</td>
<td></td>
</tr>
<tr>
<td></td>
<td>一个用户组可绑定的策略中的实例个数</td>
<td>10000</td>
<td>具体见: 大规模实例级权限限制</td>
</tr>
<tr>
<td>分级管理员</td>
<td>一个分级管理员可创建的用户组个数</td>
<td>100</td>
<td></td>
</tr>
<tr>
<td></td>
<td>一个分级管理员可添加的成员个数</td>
<td>100</td>
<td></td>
</tr>
<tr>
<td></td>
<td>所有系统可创建的分级管理员个数</td>
<td>3000</td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="23">2.3 名称限制</h3>
<ul>
<li>系统 ID(system_id) :  最大 32 个字符; 允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)</li>
<li>操作 ID(action_id) : 最大 32 个字符; 允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)</li>
<li>资源类型 ID(resource_type ID) : 最大 32 个字符; 允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)</li>
<li>用户组名称: 最大 128 (最小为 5)个字符; (分级管理员下唯一)</li>
<li>分级管理员名称: 最大 128 个字符; (全局唯一)</li>
<li>权限模板名称: 最大 128 个字符</li>
<li>常用操作: 最大 128 个字符</li>
</ul>
<h2 id="3">3. 常见问题</h2>
<h3 id="31-10000">3.1 系统有 10000 个操作需要注册, 怎么办</h3>
<p>默认操作应该是<code>可枚举</code>的, 经过评估, 平台类的大型系统, 正常操作也不会超过 100 个; </p>
<p>如果超过 100 个, 需要考虑自身的权限模型是否合理;</p>
<p>一个系统最多 100 个操作的限制, 防止某些系统每新增一个实例就注册增删改查四个操作进来, 导致用户在配置这个系统权限时基本不可用;</p>
<h3 id="32-id-32-256">3.2 操作 ID 长度 32 位限制, 能否放开到 256</h3>
<p>不能, 操作 ID 是一个操作的标识;  是权限中心数据库索引及缓存索引中一个关键值, 长度更长会导致整体的性能下降;</p>
<p>而且, 操作 ID 仅仅是标识而已, 并不需要展示给普通的用户, 所以对可读性要求不高;</p>
<p>某些系统的 ID 是 64/128/256 甚至更长的, 权限中心不可能满足所有接入需求; </p>
<p>一旦长度可能超过 32 位, 接入系统, 需要: 建立映射表关系, 自身系统的操作 ID 映射成权限的操作 ID, 鉴权时进行转换 (可以使用整数 ID, 或者字符串前缀+随机字符)</p>
<h3 id="33-10000">3.3 限制一个人同一个操作最多能配置 10000 个实例, 能否放开</h3>
<p>不能; 具体见 <a href="06-LargeScaleInstances.md">大规模实例级权限限制</a></p><h1 id="_bk_iam_approver_">资源审批人<code>_bk_iam_approver_</code>说明</h1>
<blockquote>
<p>本文重点阐述<code>_bk_iam_approver_</code>的概念及开发者如何使用</p>
</blockquote>
<h2 id="_1">背景</h2>
<p>如果系统需要使用资源实例的细粒度审批人, 就需要在资源反向拉取接口中返回实例的<code>资源审批人</code></p>
<h2 id="_bk_iam_approver__1"><code>_bk_iam_approver_</code>是什么</h2>
<p><code>_bk_iam_approver_</code>是权限中心对<code>资源审批人</code>的一种表达形式, 每个资源实例的审批人可以是多个</p>
<h2 id="_2">格式及内容</h2>
<ul>
<li>key: <code>_bk_iam_approver_</code></li>
<li>value: <code>["admin", ...]</code></li>
</ul>
<h2 id="_3">示例</h2>
<p>标准运维的任务查看为例
- 操作: <code>任务查看</code>(<code>action=task_view</code>)
- 关联资源类型 resource_type 为 <code>任务</code>(<code>system_id=bk_sops; id=task</code>)
- 在申请权限的时候, 如果指定申请<code>任务</code>为<code>task1</code>, 这时候如果配置的申请流程是实例审批人, 权限中心会回调接入系统资源反向拉取获取<code>_bk_iam_approver_</code></p>
<h2 id="_4">资源反向拉取</h2>
<ul>
<li><a href="../Reference/API/03-Callback/13-fetch_instance_info.md">资源反向拉取: 4. fetch_instance_info</a></li>
</ul>
<p>资源反向拉取获取一批实例属性的时候, 可能会要求接入系统返回实例的<code>_bk_iam_approver_</code>属性, 按照规范返回即可</p><h1 id="_1">系统注册名词规范</h1>
<h3 id="_2">「操作」注册规范</h3>
<ol>
<li>操作名，
     <code>中文</code>：采用 <code>「名称 + 动词」</code>格式，比如作业新建、后台管理。
     <code>英文</code>：采用 <code>「动词 + 名词」</code> 格式，比如 Create Jobs。</li>
<li>操作名，尽量通俗易懂，如果操作名无法直白告诉用户该操作的功能，必须 <code>填写操作描述</code> 。（mousehover 时提示用户）</li>
<li>如果一个操作需要依赖其他前置操作来完成，必须 <code>填写前置操作列表</code> 。比如「作业执行」，需要依赖前置操作「作业查看」，那么在注册「作业执行」时，需要填写关联操作「作业查看」，保证用户申请的任何一个操作都是能用的。</li>
<li>操作名的国际化处理，统一格式为 <code>「首字母大写 + 空格」</code> 。比如，「作业新建」的英文为：Job Create。</li>
<li>注册操作时，必须 <code>填写操作类型</code> ：create、delete、edit、view、list、execute、manage。（如不满足可以提需求）</li>
<li>接入系统涉及到拉取用户有权限的业务、业务集列表功能时，需要注册一个 <code>业务访问</code> 的操作权限，依赖资源可以选择<code>业务</code>、<code>业务集</code>、<code>业务和业务集</code>。（业务集相关待实现） </li>
</ol>
<h3 id="id">ID 命名规范</h3>
<ol>
<li>系统 (System) ID：只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)，最长 32 个字符。</li>
<li>资源类型 (ResoureType) ID：只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)，最长 32 个字符。</li>
<li>操作 (Action) ID：只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)， 最长 32 个字符。</li>
</ol><h1 id="api-esb-api">后台 API 和 ESB API 说明</h1>
<h2 id="_1">背景</h2>
<p>由于高性能的 APIGateway2.0 尚未发布企业版, 所以为了性能考虑, 模型/策略/鉴权等接口目前没有接入 ESB, 直接后台 API 调用; 而 SaaS 上无权限申请/授权接口等, 接入了 ESB</p>
<p>目前权限中心提供的接口分为两类:
1. 后台 API, URL 前缀: <code>/api/v1/[model | policy | systems]</code>
    1.1 model <a href="../02-Model/00-API.md">模型注册及更新 API</a>
    1.2 policy <a href="../04-Auth/01-SDK.md">策略查询 API</a> / <a href="../04-Auth/02-DirectAPI.md">直接鉴权 API</a>
    1.3 systems 系统相关  <a href="../08-Query/01-PolicyGet.md">查询策略 API</a>
2. 组件 API, URL 前缀: <code>/api/c/compapi/v2/iam/[application | authorization]</code>
    1.1  application <a href="../05-Application/01-GenerateURL.md">5. 生成无权限申请 URL</a>
    1.2  authorization <a href="../07-ResourceCreatorAction/01-Attribute.md">新建关联属性授权接口</a>
    1.3 authorization <a href="../06-GrantRevoke/01-Topology.md">资源拓扑授权/回收</a></p>
<p>未来, APIGateway 2.0 企业版发布后, 会全部统一接入 APIGateway, 对于接入系统来说, 就是一套系统, 一种调用方式.</p>
<h2 id="api">后台 API</h2>
<p>直接调用 IAM 后台 API, 请仔细阅读 <a href="./02-APIBasicInfo.md">接口协议前置说明</a> 中对 request header/body 以及 response 的说明</p>
<p>调用地址:
- 如果是企业版 SaaS, 直接通过环境变量获取: <code>BK_IAM_V3_APP_CODE</code> (权限中心 SaaS 的 app_code, 用于跳转到权限中心的 URL 拼接) / <code>BK_IAM_V3_INNER_HOST</code>(权限中心后台的访问地址)
- 如果是非 SaaS 的其他平台, 需要部署时渲染 <code>__BKIAM_HOST__:__BKIAM_PORT__</code></p>
<p>相关链接:
- <a href="../../../HowTo/FAQ/ErrorCode.md">后台接口错误码说明</a></p>
<h2 id="esb-api">ESB API</h2>
<p>需要遵守企业版 ESB 的接口协议. eedev 联调环境, 可以通过 <code>https://{PAAS_DOMAIN}/esb/api_docs/system/IAM/</code> 查看权限中心接入 ESB 的具体文档</p>
<p>ESB 调用地址:
- 如果是企业版 SaaS, 使用 ESB SDK 调用,   API 调用说明 <code>https://{PAAS_DOMAIN}/esb/guide/page/use_component</code>
- 如果是企业版 SaaS, 直接通过 http 访问, 可以通过环境变量获取: <code>BK_PAAS_INNER_HOST</code>即 PaaS 的内网域名, 拼接<code>{BK_PAAS_INNER_HOST}/api/c/compapi/v2/iam/</code>
- 如果是非企业版 SaaS 的其他平台, 请使用 PaaS 内网地址或域名访问组件 <code>{PAAS_DOMAIN}/api/c/compapi/v2/iam/</code>. </p><h2 id="_1">接口协议前置说明</h2>
<p>Request Header:</p>
<ul>
<li><code>X-Bk-App-Code</code>   蓝鲸应用 app_code</li>
<li><code>X-Bk-App-Secret</code>  蓝鲸应用 app_secret</li>
<li><code>X-Bk-IAM-Version</code> IAM Policy 协议版本号, 不传默认为 1. (只有鉴权/策略相关的接口涉及, 暂时不需要关注)</li>
</ul>
<p>Response Header:
-  <code>X-Request-Id</code>  请求 request_id, 请记录, 用于错误排查</p>
<p>Response Body: 遵循蓝鲸官方 API 协议进行返回, <code>code != 0</code> 表示出错, <code>message</code>包含具体信息</p>
<pre class="codehilite"><code class="language-bash">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {
    }
}</code></pre>


<p><strong>重要</strong>: 调用权限中心 API 都会返回一个<code>request_id</code>, 请在日志中记录, 以便后续联调及正式环境中进行问题排查; </p>
<hr />
<h2 id="resources">接口协议中<code>resources</code>字段说明</h2>
<p>Request 的 json body 中<code>resources</code></p>
<blockquote>
<p><code>resources</code>是一个列表
<code>resources</code>代表<code>一个资源</code></p>
</blockquote>
<p>如果是独立系统, 那么<code>resources</code>只有一个 item</p>
<pre class="codehilite"><code class="language-json">    &quot;resources&quot;: [
    {
        &quot;system&quot;: &quot;bk_paas&quot;,
        &quot;type&quot;: &quot;app&quot;,
        &quot;id&quot;: &quot;bk_framework&quot;
    }]</code></pre>


<p>如果是跨系统资源依赖, 那么<code>resources</code>有多个 item, 包含跨系统依赖资源, 例如 job 脚本是否有在 cmdb 某个主机上的执行权限</p>
<pre class="codehilite"><code class="language-json">    &quot;resources&quot;: [
    {
        &quot;system&quot;: &quot;bk_job&quot;,
        &quot;type&quot;: &quot;script&quot;,
        &quot;id&quot;: &quot;run&quot;
    },
    {
        &quot;system&quot;: &quot;bk_cmdb&quot;,
        &quot;type&quot;: &quot;host&quot;,
        &quot;id&quot;: &quot;192.168.1.1&quot;
    }]</code></pre>


<p>所以, 写批量接口批量确认一批资源权限
- <code>resources</code>表示一个资源, 类型是 <code>[resource,]</code>
- <code>resources_list</code>表示一批资源, 类型是 <code>[resources, resources]</code> 即, <code>[ [resource,],  [resource,], ]</code></p><h1 id="_1">系统间接口鉴权</h1>
<h2 id="-">接入系统 -&gt; 权限中心</h2>
<h3 id="1">1. 场景</h3>
<ol>
<li>模型注册 (<a href="../02-Model/00-API.md">模型注册接口协议</a>)</li>
<li>拉取策略/鉴权 (<a href="../04-Auth/01-SDK.md">SDK 鉴权接口协议</a>)</li>
</ol>
<h3 id="2">2. 鉴权逻辑</h3>
<p>使用蓝鲸 app_code/app_secret 进行鉴权 </p>
<p>Request Header:</p>
<pre class="codehilite"><code class="language-bash">X-Bk-App-Code 蓝鲸应用app_code
X-Bk-App-Secret 蓝鲸应用app_secret</code></pre>


<p>没有权限将返回:</p>
<pre class="codehilite"><code class="language-bash">status: 200
response_body:
# 没有提供app_code/app_secret
{
    &quot;code&quot;: 1901401,
    &quot;message&quot;: &quot;unauthorized: app code and app secret required&quot;,
    &quot;data&quot;: {}
}
# app_code或app_secret错误
{
    &quot;code&quot;: 1901401,
    &quot;message&quot;: &quot;unauthorized: app code or app secret wrong&quot;,
    &quot;data&quot;: {}
}</code></pre>


<hr />
<h2 id="-_1">权限中心 -&gt; 接入系统</h2>
<p>接入系统暴露的接口是可以查询资源实例/属性等信息的, 可能包含敏感信息, 所以需要对权限中心资源拉取接口做鉴权.</p>
<h3 id="1_1">1. 场景</h3>
<p>资源拉取 (<a href="../03-Callback/01-API.md">资源拉取接口协议</a>)</p>
<h3 id="2_1">2. 鉴权逻辑</h3>
<p><strong>注意</strong>: 目前只支持<code>none</code>或<code>basic</code>, 相对复杂的<code>digest</code>/<code>signature</code>规划中</p>
<ol>
<li>注册系统时(<a href="../02-Model/10-System.md">新增系统接口协议</a>), 需要确定鉴权方式: <code>none</code>/<code>basic</code>/<code>digest</code>/<code>signature</code> </li>
<li>系统注册成功, 会生成一个<code>token</code></li>
<li>当权限中心调用<code>接入系统</code>的时候, 会根据接入系统注册的鉴权方式和上一步生成的 token, 生成对应的请求, 然后调用<code>接入系统</code></li>
<li>接入系统需要根据注册系统选择的鉴权方式, 对权限中心发过来的请求进行鉴权.</li>
</ol>
<p><strong>鉴权方式:</strong>
- <code>none</code>: 不鉴权, 意味着所有资源拉取接口没有权限控制(<a href="../03-Callback/01-API.md">资源拉取接口协议</a>). <code>不推荐, 可以在测试联调时使用</code>
- <code>basic</code>: http basic auth, 权限中心调用接入系统, 生成 header<code>Authorization: Basic base64(username:password)</code> (其中<code>username=bk_iam, password={token}</code>), <code>接入系统</code>解析请求后, 要使用 token 进行鉴权.  <code>推荐, 同蓝鲸体系部署在同一个内网的服务</code> - 已支持
- <code>digest</code>: http digest auth, 权限中心调用接入系统, 使用摘要算法生成 header<code>Authorization: Digest xxxx</code>, <code>接入系统</code>解析请求后, 需要使用 token 进行鉴权. <code>同蓝鲸体系部署在同一个内网的服务, 对安全性进一步需求的服务(实现方和调用方的逻辑较为复杂, 出问题不好调试)</code> - 暂不支持
- <code>signature</code>: 使用签名算法, 生成 header<code>X-Bk-IAM-Signature: xxx</code> (尚未确认协议). <code>接入系统</code>解析请求后, 需要使用 token 进行鉴权. <code>外网服务或对安全性有很高要求的服务</code>- 暂不支持</p>
<p><code>接入系统</code>解析请求后, 需要使用 token 进行鉴权:</p>
<ul>
<li>使用<code>app_code/app_secret</code>到权限中心查询<code>token</code> (<a href="../02-Model/16-Token.md">查询 token 协议</a>) (建议, 查询回来后缓存起来)</li>
</ul><h1 id="api">模型注册 API</h1>
<ul>
<li><a href="./00-Concepts.md">名词及概念</a></li>
<li><a href="./10-System.md">系统 System</a></li>
<li><a href="./11-ResourceType.md">资源类型 ResourceType</a></li>
<li><a href="./12-InstanceSelection.md">实例视图 InstanceSelection</a></li>
<li><a href="./13-Action.md">操作 Action</a></li>
<li><a href="./14-ActionGroup.md">操作组 ActionGroup</a></li>
<li><a href="./15-CommonQuery.md">通用查询 Common Query</a></li>
<li><a href="./16-Token.md">系统 token 查询</a></li>
<li><a href="./17-CommonActions.md">常用操作配置 CommonActions</a></li>
<li><a href="./18-FeatureShieldRules.md">功能开关配置 FeatureShieldRules</a></li>
<li><a href="./19-ResourceCreatorAction.md">新建关联配置 ResourceCreatorAction</a></li>
</ul><h1 id="_1">名词及概念</h1>
<p>说明: 1. 概念 2.限制(例如正则校验/非空/全局唯一等等)</p>
<blockquote>
<p>所有更新(<code>PUT</code>)操作, 如果传了<code>key</code>并给了<code>空值</code>, 那么执行的是<code>置空操作</code>; 如果没有传<code>key</code>, 表示不更新该字段</p>
</blockquote>
<h2 id="1-system-saas">1. System: 接入权限中心的 SaaS 或平台或第三方系统</h2>
<ul>
<li>id: 系统的唯一标识，可直接使用 app_code 的值作为唯一标识，但 app_code 还用于接口的认证，值可以一样，但需支持 id 和 app_code 可单独配置不一样的，同时对于 cmdb 这种被依赖的系统，需要保证所有版本的系统 ID 都一样；只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)， 最长 32 个字符。</li>
<li>name: 系统名称，注册时权限中心不允许与已存在系统同名</li>
<li>name_en: 系统英文名，国际化时切换到英文版本显示</li>
<li>description:  系统描述</li>
<li>description_en: 系统描述描述英文, 国际化切换到英文版本展示</li>
<li>clients： 有权限调用权限中心获取或操作该系统权限相关数据的客户端列表，即 app_code list，多个使用英文逗号分隔， 比如 BCS 由一个客户端 bk_bcs 注册，但是需要多个客户端（bk_bcs,bk_bcs_app,bk_devops,bk_harbor）都可以调用鉴权接口进行该系统的鉴权 </li>
<li>provider_config.host：权限中心回调接入系统时需要的配置文件，权限中心需要调用接入系统拉取资源实例接口，所以需要接入系统 API 的 HOST, HOST 格式：scheme://netloc，与 resource_type.provider_config.path 配合使用. <code>例如system.provider_config.host=http://cmdb.consul, resource_type.provider_config.path=/api/v1/resources</code>, 那么将调用<code>http://cmdb.consul/api/v1/resources</code>去拉取该资源类型相关信息</li>
<li>provider_config.auth: 权限中心调用接入系统吸取资源信息需要用的的接口鉴权方法, 目前支持<code>none/basic</code>, (<code>digest/signature</code>规划中), 接入系统需要实现相应的鉴权逻辑, 确保是合法的 iam 请求. <a href="../01-Overview/03-APIAuth.md">系统间调用接口鉴权:权限中心-&gt;接入系统</a></li>
<li>provider_config.healthz: 权限中心调用接入系统的 healthz 检查系统是否健康; 与 provider_config.host 配合使用, <code>例如system.provider_config.host=http://cmdb.consul, provider_config.healthz=/healthz/</code>, 那么将调用<code>http://cmdb.consul/healthz/</code>检查系统是否健康. </li>
</ul>
<hr />
<h2 id="2-resourcetype">2. ResourceType: 操作对象的资源类别</h2>
<ul>
<li>id: 资源类型的唯一标识，接入系统下唯一，只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)，最长 32 个字符。</li>
<li>name: 资源类型名称，系统下唯一</li>
<li>name_en:  资源类型英文名，国际化时切换到英文版本显示</li>
<li>description: 资源类型描述</li>
<li>description_en: 资源类型描述英文, 国际化切换到英文版本展示</li>
<li>parents: 资源类型的直接上级，可多个直接上级，可以是自身系统的资源类型或其他系统的资源类型, 可为空列表，不允许重复，数据仅用于权限中心产品上显示  </li>
<li>provider_config: 权限中心调用查询资源实例接口需要的配置文件，包括权限中心调用查询资源实例接口的 URL 的 path，与 system.provider_config.host 配合使用. <code>例如system.provider_config.host=http://cmdb.consul, resource_type.provider_config.path=/api/v1/resources</code>, 那么将调用<code>http://cmdb.consul/api/v1/resources</code>去拉取该资源类型相关信息</li>
</ul>
<hr />
<h2 id="3-instanceselection">3. InstanceSelection: 实例视图</h2>
<ul>
<li>id: 实例视图的唯一标识，接入系统下唯一，只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)，最长 32 个字符。</li>
<li>name: 实例视图名称，系统下唯一</li>
<li>name_en:  实例视图英文名，国际化时切换到英文版本显示</li>
<li>resource_type_chain：实例视图包含的资源类型的层级链路</li>
<li>is_dynamic：是否是动态拓扑视图，<code>默认为false</code>，如果是动态拓扑视图, 需要在<code>list_instance</code>中实现<code>child_type</code>来拉取到下一级的资源类型, <a href="../03-Callback/12-list_instance.md">具体参考</a><ul>
<li>使用动态拓扑视图的所有下级资源类型的系统 id 必须与 root 节点的系统 id 相同, 不能出现系统 id 不同的情况, 会导致配置出错误的权限</li>
<li>使用动态拓扑视图时, 权限中心不会校验用户提交的数据是否与视图匹配, 并且在创建依赖操作时, 如果发现是动态拓扑视图, 不会产生依赖操作</li>
</ul>
</li>
</ul>
<hr />
<h2 id="4-action">4. Action: 权限操作，比如增删改查</h2>
<ul>
<li>id: 操作的唯一标识，接入系统下唯一，只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-)，最长 32 个字符。</li>
<li>name: 操作名称，系统下唯一</li>
<li>name_en:  操作英文名，国际化时切换到英文版本显示</li>
<li>description: 操作描述</li>
<li>description_en: 描述英文, 国际化切换到英文版本展示</li>
<li>type: 操作的类型，枚举值包括<code>create\delete\view\edit\list\manage\execute</code> 比如创建类操作需要标识为"create"，无法分类可为空字符串，目前权限中心仅仅对创建类操作有相关处理</li>
<li>related_actions: related_actions: 操作的依赖操作，当用户申请的操作权限必须依赖其他操作权限（暂不支持跨系统操作关联）时，比如用户申请 作业编辑，必须依赖 作业查看 的操作权限，作业查看 就是 作业编辑 的依赖操作。在产品层表现就是：当用户勾选 作业编辑 时，系统在创建申请单时，会自动申请 作业查看 权限。 </li>
<li>related_resource_types： 操作的对象资源类型列表，列表顺序与产品展示、鉴权校验 顺序 必须保持一致 <a href="../../../../权限中心/产品白皮书/术语解释/Trem.md#依赖资源">产品说明: 依赖资源</a><ul>
<li>system_id： 资源类型的来源系统，可以是自身系统或其他系统</li>
<li>scope：限制该操作对该资源的选择范围，条件表达式协议: <a href="../..//Expression/01-Schema.md">协议详情</a> <a href="../../../../权限中心/产品白皮书/术语解释/Trem.md#资源范围">产品说明: 资源范围</a></li>
<li>selection_mode: 选择类型, 即资源在权限中心产品上配置权限时的作用范围<ul>
<li>等于<code>instance</code>, 仅可选择实例, <code>默认值</code></li>
<li>等于<code>attribute</code>, 仅可配置属性, 此时<code>instance_selections</code>配置不生效</li>
<li>等于<code>all</code>, 可以同时选择实例和配置属性</li>
</ul>
</li>
<li>related_instance_selections：关联的实例视图，可以关联本系统定义的实例视图, 也可以配置其他系统定义的(如果<code>selection_mode=attribute</code>不用配置该字段). 该字段的功能表现在权限中心产品上配置权限时的实例选择方式 <a href="../../../../权限中心/产品白皮书/术语解释/Trem.md#实例视图">产品说明: 实例选择视图</a><ul>
<li>system_id：实例视图的系统</li>
<li>id：实例视图的 ID</li>
<li>ignore_iam_path：是否忽略路径，<code>默认为false</code>，在 IAM 产品上选择实例视图配置权限的资源时，<strong>如果选到 Action 关联的资源类型实例，而不是上级或祖先（选择了中间节点，ignore_iam_path 是不起作用的）</strong>，那么对于<code>ignore_iam_path=true</code>时权限保存类似：<code>id=192.168.1.1</code>，若<code>ignore_iam_path=false</code>时则权限保存类似：<code>id=192.168.1.1 AND _bk_iam_path_= /biz,1/set,2/module,3/</code><ul>
<li>ignore_iam_path 由 false 变更为 true 时，已配置的权限（类似：<code>id=192.168.1.1 AND _bk_iam_path_= /biz,1/set,2/module,3/</code>）将无法通过 id 直接通过鉴权</li>
<li>ignore_iam_path 由 true 变更为 false 时，已配置的权限（类似：<code>id=192.168.1.1</code>）无论任何路径都可以通过鉴权</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="5-version">5.版本号 version</h2>
<ul>
<li>仅仅作为在权限中心产品上进行 New 的更新提醒。<a href="../../../../权限中心/产品白皮书/术语解释/Trem.md#版本">产品说明：版本号</a></li>
<li>对于 ResourceType，对比该系统的所有 ResourceType 的 Version，最大的 version 将在产品上显示 New 的提示</li>
<li>对于 Action，对比该系统的所有 Action 的 Version，最大的 version 将在产品上显示 New 的提示</li>
</ul><h1 id="system-api">系统 System API</h1>
<h3 id="_1">参数说明</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">系统 id, 全局唯一, 只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-), 最长 32 个字符.</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">系统名称，全局唯一</td>
</tr>
<tr>
<td align="left">name_en</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">系统英文名，国际化时切换到英文版本显示</td>
</tr>
<tr>
<td align="left">description</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">系统描述，全局唯一</td>
</tr>
<tr>
<td align="left">description_en</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">系统描述英文，国际化时切换到英文版本显示</td>
</tr>
<tr>
<td align="left">clients</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">有权限调用的客户端，即有权限调用的 app_code 列表，多个使用英文逗号分隔，注册系统时会校验 Header 头里的 app_code 必须在列表里 <a href="./00-Concepts.md">更多概念说明</a></td>
</tr>
<tr>
<td align="left">provider_config</td>
<td align="left">Object</td>
<td align="left">是</td>
<td align="left">权限中心回调接入系统的配置文件 <a href="./00-Concepts.md">更多概念说明</a></td>
</tr>
</tbody>
</table>
<p>provider_config 内元素 参数：</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">host</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">权限中心调用查询资源实例接口的 HOST，格式：scheme://netloc，与 resource_type.provider_config.path 配合使用</td>
</tr>
<tr>
<td align="left">auth</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">权限中心调用查询资源实例接口的鉴权方式, 当前可选: <code>none</code>/<code>basic</code>, 详细说明文档 <a href="../01-Overview/03-APIAuth.md">系统间调用接口鉴权:权限中心-&gt;接入系统</a></td>
</tr>
<tr>
<td align="left">healthz</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">权限中心调用接入系统的 healthz 检查系统是否健康; 与 provider_config.host 配合使用, <code>例如system.provider_config.host=http://cmdb.consul, provider_config.healthz=/healthz/</code>, 那么将调用<code>http://cmdb.consul/healthz/</code>检查系统是否健康.</td>
</tr>
</tbody>
</table>
<h3 id="1-system">1. 新增 system</h3>
<p>注意: </p>
<ul>
<li>一个 app_code 只能创建一个 system, 且 system_id 必须等于 app_code; 如果不符合要求, 接口返回 <code>1901400 bad request:system_id should be the app_code!</code></li>
<li>创建 system 时如果没有把自己加入 clients, 会自动将当前发起<code>新增system</code>的 app_code 加入<code>clients</code></li>
</ul>
<hr />
<h4 id="url">URL</h4>
<blockquote>
<p>POST /api/v1/model/systems</p>
</blockquote>
<h4 id="request">Request</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;id&quot;: &quot;bk_cmdb&quot;,
    &quot;name&quot;: &quot;配置平台&quot;,
    &quot;name_en&quot;: &quot;CMDB&quot;,
    &quot;description&quot;: &quot;配置平台是一个...&quot;,
    &quot;description_en&quot;: &quot;CMDB is a...&quot;,
    &quot;clients&quot;: &quot;bk_cmdb,cmdb&quot;,
    &quot;provider_config&quot;: {
        &quot;host&quot;: &quot;http://cmdb.service.consul&quot;,
        &quot;auth&quot;: &quot;basic&quot;,
        &quot;healthz&quot;: &quot;/api/v1/healthz&quot;
    }
}</code></pre>


<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {
        &quot;id&quot;: &quot;bk_cmdb&quot;
    }
}</code></pre>


<h3 id="2-system">2. 更新 system</h3>
<p><code>路径中system_id是唯一标识; body中只需要传入要更新的字段, 其中对于provider_config是全覆盖更新，不支持只更新provider_config中某个字段</code></p>
<p>注意: 
- 更新 system 时如果没有把自己加入 clients, 会自动将当前发起<code>更新system</code>的 app_code 加入<code>clients</code>(即, 更新发起者无法将自己移除<code>clients</code>)</p>
<h4 id="url_1">URL</h4>
<blockquote>
<p>PUT /api/v1/model/systems/{system_id}</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
</tbody>
</table>
<h4 id="request_1">Request</h4>
<p><code>json
{
    "name": "配置平台",
    "name_en": "CMDB",
    "clients": "bk_cmdb,cmdb",
    "provider_config": {
        "host": "http://cmdb_new.service.consul"
    }
}</code></p>
<h4 id="response_1">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre><h1 id="resourcetype-api">资源类型 ResourceType API</h1>
<h3 id="_1">参数说明</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型 id, 系统下唯一, 只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-),最长 32 个字符.</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型名称，系统下唯一</td>
</tr>
<tr>
<td align="left">name_en</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型英文名，国际化时切换到英文版本显示</td>
</tr>
<tr>
<td align="left">description</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">资源类型名称，系统下唯一</td>
</tr>
<tr>
<td align="left">description_en</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">资源类型英文名，国际化时切换到英文版本显示</td>
</tr>
<tr>
<td align="left">parents</td>
<td align="left">Array[Object]</td>
<td align="left">否</td>
<td align="left">资源类型的直接上级，可多个直接上级，可以是自身系统的资源类型或其他系统的资源类型, 可为空列表，不允许重复，数据仅用于权限中心产品上显示</td>
</tr>
<tr>
<td align="left">provider_config</td>
<td align="left">Object</td>
<td align="left">是</td>
<td align="left">权限中心调用查询资源实例接口的配置文件，与 system.provider_config.host 配合使用 <a href="./00-Concepts.md">更多概念说明</a></td>
</tr>
<tr>
<td align="left">version</td>
<td align="left">int</td>
<td align="left">否</td>
<td align="left">版本号，允许为空，仅仅作为在权限中心上进行 New 的更新提醒  <a href="./00-Concepts.md">更多概念说明</a></td>
</tr>
</tbody>
</table>
<p>parents 元素参数说明</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">直接上级资源类型的来源系统 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">直接上级资源类型 ID</td>
</tr>
</tbody>
</table>
<p>provider_config 内元素 参数：</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">path</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">权限中心调用查询资源实例接口的 URL 的 PATH，与 system.provider_config.host 配合使用</td>
</tr>
</tbody>
</table>
<h3 id="1-resourcetype">1. 新增 resourceType</h3>
<p>限制:
- 一个系统只能创建最多 50 个 resourceType</p>
<h4 id="url">URL</h4>
<blockquote>
<p>POST /api/v1/model/systems/{system_id}/resource-types</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<pre class="codehilite"><code class="language-json">[
    {
        &quot;id&quot;: &quot;biz_set&quot;,
        &quot;name&quot;: &quot;业务集&quot;,
        &quot;name_en&quot;: &quot;biz_set&quot;,
        &quot;description&quot;: &quot;业务集是...&quot;,
        &quot;description_en&quot;: &quot;biz_set is a ...&quot;,
        &quot;parents&quot;: [],
        &quot;provider_config&quot;: {
            &quot;path&quot;: &quot;/api/v1/resources/biz_set/query&quot;
        },
        &quot;version&quot;: 1
    },
    {
        &quot;id&quot;: &quot;biz&quot;,
        &quot;name&quot;: &quot;业务&quot;,
        &quot;name_en&quot;: &quot;biz&quot;,
        &quot;description&quot;: &quot;业务是...&quot;,
        &quot;description_en&quot;: &quot;biz is a ...&quot;,
        &quot;parents&quot;: [
            {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;biz_set&quot;}            
        ],
        &quot;provider_config&quot;: {
            &quot;path&quot;: &quot;/api/v1/resources/biz/query&quot;
        },
        &quot;version&quot;: 1
    },
    {
        &quot;id&quot;: &quot;dir&quot;, 
        &quot;name&quot;: &quot;目录&quot;,
        &quot;name_en&quot;: &quot;dir&quot;, 
        &quot;description&quot;: &quot;目录是...&quot;,
        &quot;description_en&quot;: &quot;dir is a ...&quot;,
        &quot;parents&quot;: [
            {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;biz&quot;}
        ],
        &quot;provider_config&quot;: {
            &quot;path&quot;: &quot;/api/v1/resources/dir/query&quot;
        },
        &quot;version&quot;: 1
    },  
    {
        &quot;id&quot;: &quot;set&quot;, 
        &quot;name&quot;: &quot;集群&quot;,
        &quot;name_en&quot;: &quot;set&quot;, 
        &quot;description&quot;: &quot;集群是...&quot;,
        &quot;description_en&quot;: &quot;set is a ...&quot;,
        &quot;parents&quot;: [
            {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;biz&quot;},
            {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;dir&quot;}
        ],
        &quot;provider_config&quot;: {
            &quot;path&quot;: &quot;/api/v1/resources/set/query&quot;
        },
        &quot;version&quot;: 1
    },
    {
        &quot;id&quot;: &quot;module&quot;, 
        &quot;name&quot;: &quot;模块&quot;,
        &quot;name_en&quot;: &quot;module&quot;, 
        &quot;description&quot;: &quot;模块是...&quot;,
        &quot;description_en&quot;: &quot;module is a ...&quot;,
        &quot;parents&quot;: [
            {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;set&quot;}
        ],
        &quot;provider_config&quot;: {
            &quot;path&quot;: &quot;/api/v1/resources/module/query&quot;
        },
        &quot;version&quot;: 1
    },
    {
        &quot;id&quot;: &quot;host&quot;, 
        &quot;name&quot;: &quot;主机&quot;,
        &quot;name_en&quot;: &quot;host&quot;, 
        &quot;description&quot;: &quot;主机是...&quot;,
        &quot;description_en&quot;: &quot;host is a ...&quot;,
        &quot;parents&quot;: [
            {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;module&quot;}
        ],
        &quot;provider_config&quot;: {
            &quot;path&quot;: &quot;/api/v1/resources/host/query&quot;
        },
        &quot;version&quot;: 1
    }
]</code></pre>


<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre>


<h3 id="2-resourcetype">2. 修改 resourceType</h3>
<h4 id="url_1">URL</h4>
<blockquote>
<p>PUT /api/v1/model/systems/{system_id}/resource-types/{resource_type_id}</p>
</blockquote>
<h4 id="parameters_1">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">resource_type_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">资源类型 ID</td>
</tr>
</tbody>
</table>
<h4 id="request_1">Request</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;name&quot;: &quot;业务新&quot;,
    &quot;name_en&quot;: &quot;biz new&quot;,
    &quot;description&quot;: &quot;业务新...&quot;,
    &quot;description_en&quot;: &quot;biz new is ....&quot;,
    &quot;provider_config&quot;: {
        &quot;path&quot;: &quot;/api/v2/resources/biz/query&quot;
    },
    &quot;version&quot;: 2
}</code></pre>


<h4 id="response_1">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre>


<h3 id="3-resourcetype">3. 删除 resourceType</h3>
<p>必须同时满足以下两个条件才能成功删除资源类型
1. 该资源类型不作为其他的上级资源，具体遍历所有资源类型的 parents 是否存在该资源类型
2. 该资源类型不作为 Action 的操作对象资源类型，具体遍历所有 Action 的 related_resource_types 是否存在该资源类型</p>
<h4 id="url_2">URL</h4>
<p>批量删除 (需要 Request.Body)</p>
<blockquote>
<p>DELETE /api/v1/model/systems/{system_id}/resource-types</p>
</blockquote>
<p>单个删除 (不需要 Request.Body)</p>
<blockquote>
<p>DELETE /api/v1/model/systems/{system_id}/resource-types/{resource_type_id}</p>
</blockquote>
<h4 id="parameters_2">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">resource_type_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">资源类型 ID</td>
</tr>
<tr>
<td align="left">check_existence</td>
<td align="left">boolean</td>
<td align="left">否</td>
<td align="left">query</td>
<td align="left">默认会检查 id 存在, 不存在将导致删除失败,  设置 false 不检查 id 是否存在, 直接走删除(<code>delete from table where id in []</code>)</td>
</tr>
</tbody>
</table>
<h4 id="request_2">Request</h4>
<pre class="codehilite"><code class="language-json">[
    {
        &quot;id&quot;: &quot;biz&quot;
    },
    {
        &quot;id&quot;: &quot;set&quot;
    }
]</code></pre>


<h4 id="response_2">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre><h1 id="instanceselection-api">实例视图 InstanceSelection API</h1>
<h3 id="_1">参数说明</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">实例视图 id, 系统下唯一, 只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-),最长 32 个字符.</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">实例视图名称，系统下唯一</td>
</tr>
<tr>
<td align="left">name_en</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">实例视图的英文名，国际化时切换到英文版本显示，系统下唯一</td>
</tr>
<tr>
<td align="left">is_dynamic</td>
<td align="left">bool</td>
<td align="left">否</td>
<td align="left">是否是动态拓扑视图，<code>默认为false</code>，<a href="./00-Concepts.md">更多概念说明</a></td>
</tr>
<tr>
<td align="left">resource_type_chain</td>
<td align="left">Array(Object)</td>
<td align="left">是</td>
<td align="left">资源类型的层级链路</td>
</tr>
</tbody>
</table>
<p>resource_type_chain 里的元素 </p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型的来源系统 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型 ID</td>
</tr>
</tbody>
</table>
<h3 id="1-instanceselection">1. 新增 instanceSelection</h3>
<p>限制:
- 一个系统只能创建最多 50 个 instanceSelection</p>
<h4 id="url">URL</h4>
<blockquote>
<p>POST /api/v1/model/systems/{system_id}/instance-selections</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<pre class="codehilite"><code class="language-json">[
    {
        &quot;id&quot;: &quot;free_host&quot;,
        &quot;name&quot;: &quot;空闲主机&quot;,
        &quot;name_en&quot;: &quot;free host&quot;,
        &quot;resource_type_chain&quot;: [{
            &quot;system_id&quot;: &quot;bk_cmdb&quot;,
            &quot;id&quot;: &quot;host&quot;
        }]
    },
    {
        &quot;id&quot;: &quot;biz_topology&quot;,
        &quot;name&quot;: &quot;业务拓扑&quot;,
        &quot;name_en&quot;: &quot;biz topology&quot;,
        &quot;resource_type_chain&quot;: [{
                &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                &quot;id&quot;: &quot;biz&quot;
            },
            {
                &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                &quot;id&quot;: &quot;set&quot;
            },
            {
                &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                &quot;id&quot;: &quot;module&quot;
            },
            {
                &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                &quot;id&quot;: &quot;host&quot;
            }
        ]
    }
]</code></pre>


<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre>


<h3 id="2-instanceselection">2. 修改 instanceSelection</h3>
<h4 id="url_1">URL</h4>
<blockquote>
<p>PUT /api/v1/model/systems/{system_id}/instance-selections/{instance_selection_id}</p>
</blockquote>
<h4 id="parameters_1">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">instance_selection_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">实例视图 ID</td>
</tr>
</tbody>
</table>
<h4 id="request_1">Request</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;id&quot;: &quot;free_host1&quot;,
    &quot;name&quot;: &quot;空闲主机1&quot;,
    &quot;name_en&quot;: &quot;free host1&quot;,
    &quot;resource_type_chain&quot;: [{
        &quot;system_id&quot;: &quot;bk_cmdb&quot;,
        &quot;id&quot;: &quot;host&quot;
    }]
}</code></pre>


<h4 id="response_1">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre>


<h3 id="3-instanceselection">3. 删除 instanceSelection</h3>
<p>必须满足以下条件才能成功删除实例视图:
1. 该实例视图没有被本系统的 Action 关联资源操作引用，具体遍历所有 Action 的 related_resource_types 中的 related_instance_selections 是否存在该实例视图</p>
<h4 id="url_2">URL</h4>
<p>批量删除 (需要 Request.Body)</p>
<blockquote>
<p>DELETE  /api/v1/model/systems/{system_id}/instance-selections</p>
</blockquote>
<p>单个删除 (不需要 Request.Body)</p>
<blockquote>
<p>DELETE /api/v1/model/systems/{system_id}/instance-selections/{instance_selection_id}</p>
</blockquote>
<h4 id="parameters_2">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">instance_selection_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">实例视图 ID</td>
</tr>
<tr>
<td align="left">check_existence</td>
<td align="left">boolean</td>
<td align="left">否</td>
<td align="left">query</td>
<td align="left">默认会检查 id 存在, 不存在将导致删除失败, 设置 false 不检查 id 是否存在, 直接走删除( <code>delete from table where id in []</code> )</td>
</tr>
</tbody>
</table>
<h4 id="request_2">Request</h4>
<pre class="codehilite"><code class="language-json">[
    {
        &quot;id&quot;: &quot;free_host&quot;
    },
    {
        &quot;id&quot;: &quot;biz_topology&quot;
    }
]</code></pre>


<h4 id="response_2">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre><h1 id="action-api">操作 Action API</h1>
<h3 id="_1">参数说明</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">操作 id, 系统下唯一, 只允许小写字母开头、包含小写字母、数字、下划线(_)和连接符(-). 最长 32 个字符.</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">操作名称，系统下唯一，参考<a href="../../NamingRules.md">命名规范</a></td>
</tr>
<tr>
<td align="left">name_en</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">操作英文名，国际化时切换到英文版本显示，参考<a href="../../NamingRules.md">命名规范</a></td>
</tr>
<tr>
<td align="left">description</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">操作描述</td>
</tr>
<tr>
<td align="left">description_en</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">操作描述英文，国际化时切换到英文版本显示</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">操作的类型，枚举值包括<code>create\delete\view\edit\list\manage\execute\use</code> 比如创建类操作需要标识为"create"，无法分类可为空字符串</td>
</tr>
<tr>
<td align="left">related_resource_types</td>
<td align="left">Array(Object)</td>
<td align="left">否</td>
<td align="left">操作的对象，资源类型列表，列表顺序与<code>产品展示</code>、<code>鉴权校验</code> 顺序 必须保持一致。<code>如果操作无需关联资源实例，这里为空即可。</code>  <strong>注意这是一个有序的列表!</strong>:</td>
</tr>
<tr>
<td align="left">related_actions</td>
<td align="left">Array(string)</td>
<td align="left">否</td>
<td align="left">操作的依赖操作, 由操作 ID 组成的字符串列表, 用于在申请权限时同时创建依赖权限  <a href="./00-Concepts.md">更多概念说明</a></td>
</tr>
<tr>
<td align="left">version</td>
<td align="left">int</td>
<td align="left">否</td>
<td align="left">版本号，允许为空，仅仅作为在权限中心上进行 New 的更新提醒 <a href="./00-Concepts.md">更多概念说明</a></td>
</tr>
</tbody>
</table>
<p>related_resource_types 里的元素</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型的来源系统，可以是自身系统或其他系统</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型 ID，操作关联多个资源类型时，<code>同一个related_resource_types里 id 不能重复</code></td>
</tr>
<tr>
<td align="left">name_alias</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">资源类型名称的别名，同一个资源类型对于不同 Action 可以有各自的显示名称</td>
</tr>
<tr>
<td align="left">name_alias_en</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">资源类型名称的别名英文名</td>
</tr>
<tr>
<td align="left">selection_mode</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">选择类型, 即资源在权限中心产品上配置权限时的作用范围, 可选: <code>instance</code>/<code>attribute</code>/<code>all</code>, 如果不设置, 默认为<code>instance</code>, <a href="./00-Concepts.md">更多概念说明</a></td>
</tr>
<tr>
<td align="left">related_instance_selections</td>
<td align="left">Array(Object)</td>
<td align="left">否</td>
<td align="left">关联的实例视图，即资源在权限中心产品上配置权限时的选择方式; 可以配置本系统的实例视图, 也可以配置其他系统的实例视图(如果<code>selection_mode=attribute</code>则该字段不用配置; 如果没有设置<code>selection_mode</code>或<code>selection_mode=instance/all</code>, 此时这个字段不能为空)</td>
</tr>
</tbody>
</table>
<p>related_instance_selections 里的元素 </p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">实例视图的来源系统 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">实例视图 ID</td>
</tr>
<tr>
<td align="left">ignore_iam_path</td>
<td align="left">bool</td>
<td align="left">否</td>
<td align="left">是否配置的权限忽略路径，<code>默认为false</code>，<a href="./00-Concepts.md">更多概念说明</a></td>
</tr>
</tbody>
</table>
<p>注册后，IAM 配置权限时拉取资源的逻辑，请查看<a href="../03-Callback/01-API.md">资源拉取接口协议</a></p>
<p><strong>重要说明：</strong> 
- Action 关联的资源类型必须在权限中心已经注册的，否则 Action 将注册失败
- 若关联的资源类型的自身系统的，则需要先注册该资源类型
- 若关联的资源类型是依赖其他系统的，则需要等依赖系统注册该资源类型后才可以进行该 Action 注册</p>
<h3 id="1-action">1. 添加 action</h3>
<p>限制:
- 一个系统只能创建最多 100 个 action, 所以如果操作会超过 100 个, 需要思考模型的正确性/合理性(例如把实例抽象到了 action 导致 action 随实例增多而增多)</p>
<h4 id="url">URL</h4>
<blockquote>
<p>POST  /api/v1/model/systems/{system_id}/actions</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<pre class="codehilite"><code class="language-json">[
    {
        &quot;id&quot;: &quot;biz_create&quot;,
        &quot;name&quot;: &quot;业务创建&quot;,
        &quot;name_en&quot;: &quot;biz_create&quot;,
        &quot;description&quot;: &quot;业务创建是...&quot;,
        &quot;description_en&quot;: &quot;biz_create is...&quot;,
        &quot;type&quot;: &quot;create&quot;,
        &quot;related_resource_types&quot;: [],
        &quot;version&quot;: 1
    },
    {
        &quot;id&quot;: &quot;host_edit&quot;,
        &quot;name&quot;: &quot;主机编辑&quot;,
        &quot;name_en&quot;: &quot;host_edit&quot;,
        &quot;type&quot;: &quot;&quot;,
        &quot;related_resource_types&quot;: [
            {
                &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                &quot;id&quot;: &quot;host&quot;,
                &quot;name_alias&quot;:  &quot;&quot;,
                &quot;name_alias_en&quot;: &quot;&quot;,
                &quot;selection_mode&quot;: &quot;instance&quot;,
                &quot;related_instance_selections&quot;: [
                    {
                        &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                        &quot;id&quot;: &quot;free_host&quot;,
                        &quot;ignore_iam_path&quot;: false,
                    }, 
                    {
                        &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                        &quot;id&quot;: &quot;biz_topology&quot;,
                        &quot;ignore_iam_path&quot;: false,
                    }, 
                    {
                        &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                        &quot;id&quot;: &quot;biz_set_topology&quot;,
                        &quot;ignore_iam_path&quot;: false,
                    }
                ]
            }
        ],
        &quot;related_actions&quot;: [&quot;view&quot;, &quot;delete&quot;],
        &quot;version&quot;: 1
    }
]</code></pre>


<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre>


<h3 id="2-action">2. 修改 action</h3>
<p><strong>重点：</strong>
- 可更新 name\name_en\type\version\related_resource_types 这 5 个 key 的值， 如果传了对应<code>key</code>并给了<code>空值</code>, 那么执行的是<code>置空操作</code>; 如果没有传<code>key</code>, 表示不更新该字段；
- <code>特别：对于related_resource_types是一个完全覆盖操作，不能单独更新related_resource_types里的某个key的值</code></p>
<h4 id="url_1">URL</h4>
<blockquote>
<p>PUT /api/v1/model/systems/{system_id}/actions/{action_id}</p>
</blockquote>
<h4 id="parameters_1">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">action_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">操作 ID</td>
</tr>
</tbody>
</table>
<h4 id="request_1">Request</h4>
<pre class="codehilite"><code class="language-json">{
   &quot;name&quot;:&quot;主机编辑New&quot;,
   &quot;name_en&quot;:&quot;host_edit&quot;,
   &quot;description&quot;:&quot;主机编辑New是...&quot;,
   &quot;description_en&quot;:&quot;host_edit is...&quot;,
   &quot;related_resource_types&quot;:[
      {
         &quot;system_id&quot;:&quot;bk_cmdb&quot;,
         &quot;id&quot;:&quot;host&quot;,
         &quot;name_alias&quot;:&quot;&quot;,
         &quot;name_alias_en&quot;:&quot;&quot;,
         &quot;selection_mode&quot;: &quot;instance&quot;,
         &quot;related_instance_selections&quot;:[
                    {
                        &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                        &quot;id&quot;: &quot;free_host&quot;,
                        &quot;ignore_iam_path&quot;: false,
                    }, 
                    {
                        &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                        &quot;id&quot;: &quot;biz_topology&quot;,
                        &quot;ignore_iam_path&quot;: false,
                    }
         ]
      }
   ],
   &quot;related_actions&quot;: [&quot;view&quot;, &quot;delete&quot;],
   &quot;version&quot;:2
}</code></pre>


<h4 id="response_1">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre>


<h3 id="3-action">3. 删除 action</h3>
<p>说明：
- 删除 Action 成功后，将会删除该 Action 相关权限，该删除操作不可逆，请谨慎调用</p>
<h4 id="url_2">URL</h4>
<p>批量删除 (需要 Request.Body)</p>
<blockquote>
<p>DELETE  /api/v1/model/systems/{system_id}/actions</p>
</blockquote>
<p>单个删除 (不需要 Request.Body)</p>
<blockquote>
<p>DELETE /api/v1/model/systems/{system_id}/actions/{action_id}</p>
</blockquote>
<h4 id="parameters_2">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">action_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">操作 ID</td>
</tr>
<tr>
<td align="left">check_existence</td>
<td align="left">boolean</td>
<td align="left">否</td>
<td align="left">query</td>
<td align="left">默认会检查 id 存在, 不存在将导致删除失败, 设置 false 不检查 id 是否存在, 直接走删除( <code>delete from table where id in []</code> )</td>
</tr>
</tbody>
</table>
<h4 id="request_2">Request</h4>
<pre class="codehilite"><code class="language-json">[
    {
        &quot;id&quot;: &quot;host_edit&quot;
    }
]</code></pre>


<h4 id="response_2">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre><h1 id="actiongroup-api">操作组 ActionGroup API</h1>
<h3 id="_1">参数说明</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">操作组名称</td>
</tr>
<tr>
<td align="left">name_en</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">操作组英文名，国际化时切换到英文版本显示</td>
</tr>
<tr>
<td align="left">actions</td>
<td align="left">Array(Object)</td>
<td align="left">否</td>
<td align="left">操作列表</td>
</tr>
<tr>
<td align="left">sub_groups</td>
<td align="left">Array(Object)</td>
<td align="left">否</td>
<td align="left">下一级操作组</td>
</tr>
</tbody>
</table>
<p>注意:</p>
<ol>
<li>最多<code>两级</code>操作组(即第一级<code>sub_gropus</code>下的操作组不能有下一级<code>sub_groups</code>), 如果嵌套超过两级, 会返回错误 <code>1901400(more than 2-levels action_group, current only support 2-levels)</code> </li>
<li>同一个操作组的<code>actions</code>和<code>sub_groups</code> 不能同时为空 <code>1901400(actions and sub_groups can't be empty at the same time)</code></li>
<li>action 可以挂在一级或二级的<code>操作组</code>上, 但是, 同一个 action 只能挂在一个<code>一级操作组</code>/<code>二级操作组</code>下; 即, action_id 全局 json 内唯一;   <code>1901400(one action can belong only one group)</code> </li>
<li>会校验每一个<code>action_id</code>; 必须是系统注册的合法<code>action_id</code>; 所以使用接口调用注册或者使用 migration 注册时, <code>action_id</code>对应的操作必须先注册, 再更新<code>action_groups</code></li>
</ol>
<h3 id="1">1. 注册或更新 操作组</h3>
<h4 id="url">URL</h4>
<p>注册</p>
<blockquote>
<p>POST /api/v1/model/systems/{system_id}/configs/action_groups</p>
</blockquote>
<p>更新 (整个列表完全覆盖更新)</p>
<blockquote>
<p>PUT /api/v1/model/systems/{system_id}/configs/action_groups</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<pre class="codehilite"><code class="language-json">[
    {
        &quot;name&quot;: &quot;管理权限&quot;,
        &quot;name_en&quot;: &quot;Admin Permissions&quot;,
        &quot;actions&quot;: [
            {
                &quot;id&quot;: &quot;create_biz&quot;
            },
            {
                &quot;id&quot;: &quot;delete_biz&quot;
            }
        ]
    },
    {
        &quot;name&quot;: &quot;运维&quot;,
        &quot;name_en&quot;: &quot;Devops Permissions&quot;,
        &quot;sub_groups&quot;: [
            {
                &quot;name&quot;: &quot;主机权限&quot;,
                &quot;name_en&quot;: &quot;Host Permissions&quot;,
                &quot;actions&quot;: [
                    {
                        &quot;id&quot;: &quot;view_host&quot;
                    },
                    {
                        &quot;id&quot;: &quot;create_host&quot;
                    }
                ]
            }
        ]
    }
]</code></pre>


<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre><h1 id="common-query-api">通用查询 Common Query API</h1>
<h3 id="1">1. 查询系统注册的信息</h3>
<h4 id="url">URL</h4>
<blockquote>
<p>GET /api/v1/model/systems/{system_id}/query</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">fields</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">query</td>
<td align="left">需要查询的信息类型，枚举值：base_info(基础信息), resource_types(资源类型)，actions(操作)，action_groups (操作组), instance_selections(实例视图), resource_creator_actions(新建关联配置), common_actions(常用操作) 多个以英文逗号分隔，空值时查询所有注册的信息</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<pre class="codehilite"><code class="language-json">fields=base_info,resource_types,actions,action_groups,instance_selections,resource_creator_actions</code></pre>


<h4 id="response">Response</h4>
<p>说明：
- 返回的信息数据结构与注册时的数据结构一致</p>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {
        // 基础信息
        &quot;base_info&quot;: {
            &quot;id&quot;: &quot;bk_cmdb&quot;,
            &quot;name&quot;: &quot;配置平台&quot;,
            &quot;name_en&quot;: &quot;CMDB&quot;,
            &quot;description&quot;: &quot;配置平台是...&quot;,
            &quot;description_en&quot;: &quot;CMDB is...&quot;,
            &quot;clients&quot;: &quot;bk_cmdb,cmdb&quot;,
            &quot;provider_config&quot;: {
                &quot;host&quot;: &quot;http://cmdb.service.consul&quot;,
                &quot;auth&quot;: &quot;basic&quot;
            }
        },
        // 资源类型
        &quot;resource_types&quot;: [
            {
                &quot;id&quot;: &quot;host&quot;, 
                &quot;name&quot;: &quot;主机&quot;,
                &quot;name_en&quot;: &quot;host&quot;, 
                &quot;description&quot;: &quot;主机是...&quot;,
                &quot;description_en&quot;: &quot;host is...&quot;, 
                &quot;parents&quot;: [
                    {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;module&quot;}
                ],
                &quot;provider_config&quot;: {
                    &quot;path&quot;: &quot;/api/v1/resources/host/query&quot;
                }
                &quot;version&quot;: 1
           }, 
           {
                &quot;id&quot;: &quot;biz&quot;,
                &quot;name&quot;: &quot;业务&quot;,
                &quot;name_en&quot;: &quot;biz&quot;,
                &quot;description&quot;: &quot;业务是...&quot;,
                &quot;description_en&quot;: &quot;biz is...&quot;,
                &quot;parents&quot;: [
                    {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;biz_set&quot;}            
                ],
                &quot;provider_config&quot;: {
                    &quot;path&quot;: &quot;/api/v1/resources/biz_set/query&quot;
                }
                &quot;version&quot;: 1
            }
        ],
        // 操作
        &quot;actions&quot;: [
            {
                &quot;id&quot;: &quot;host_edit&quot;,
                &quot;name&quot;: &quot;主机编辑New&quot;,
                &quot;name_en&quot;: &quot;host_edit&quot;,
                &quot;description&quot;: &quot;主机编辑New是...&quot;,
                &quot;description_en&quot;: &quot;host_edit is...&quot;,
                &quot;type&quot;: &quot;&quot;,
                &quot;related_resource_types&quot;: [
                    {
                        &quot;system_id&quot;: &quot;bk_cmdb&quot;,
                        &quot;id&quot;: &quot;host&quot;,
                        &quot;name_alias&quot;:  &quot;服务器&quot;,
                        &quot;name_alias_en&quot;: &quot;server&quot;,
                        &quot;instance_selections&quot;: [
                            {
                                &quot;name&quot;: &quot;资源池主机&quot;,
                                &quot;name_en&quot;: &quot;free host&quot;,
                                &quot;resource_type_chain&quot;: [{&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;host&quot;}]
                            }, 
                            {
                                &quot;name&quot;: &quot;业务拓扑&quot;,
                                &quot;name_en&quot;: &quot;biz topology&quot;,
                                &quot;resource_type_chain&quot;: [{&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;biz&quot;}, {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;set&quot;}, {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;module&quot;}, {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;host&quot;}]
                            },
                            {
                                &quot;name&quot;: &quot;业务集拓扑&quot;,
                                &quot;name_en&quot;: &quot;biz set topology&quot;
                                &quot;resource_type_chain&quot;: [{&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;biz_set&quot;}, {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;set&quot;}, {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;module&quot;}, {&quot;system_id&quot;: &quot;bk_cmdb&quot;, &quot;id&quot;: &quot;host&quot;}]
                            }
                        ]
                    }
                ],
                &quot;version&quot;: 1,
            }
        ],
        // 实例视图
        &quot;instance_selections&quot;: [
            {
                &quot;id&quot;: &quot;view1&quot;,
                &quot;name&quot;: &quot;实例选择11&quot;,
                &quot;name_en&quot;: &quot;view11&quot;,
                &quot;resource_type_chain&quot;: [
                    {
                        &quot;id&quot;: &quot;bbbdd&quot;,
                        &quot;system_id&quot;: &quot;aaacc&quot;
                    }
                ]
            }
        ],
        &quot;resource_creator_actions&quot;: {
            &quot;config&quot;:[
                {
                    &quot;id&quot;:&quot;biz&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;biz_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;biz_view&quot;,
                            &quot;required&quot;:true
                        },
                        {
                            &quot;id&quot;:&quot;set_create&quot;,
                            &quot;required&quot;:false
                        }
                    ],
                    &quot;sub_resource_types&quot;:[
                        {
                            &quot;id&quot;:&quot;set&quot;,
                            &quot;actions&quot;:[
                                {
                                    &quot;id&quot;:&quot;set_edit&quot;,
                                    &quot;required&quot;:false
                                },
                                {
                                    &quot;id&quot;:&quot;set_view&quot;,
                                    &quot;required&quot;:false
                                },
                                {
                                    &quot;id&quot;:&quot;module_create&quot;,
                                    &quot;required&quot;:false
                                }
                            ],
                            &quot;sub_resource_types&quot;:[
                                {
                                    &quot;id&quot;:&quot;module&quot;,
                                    &quot;actions&quot;:[
                                        {
                                            &quot;id&quot;:&quot;module_edit&quot;,
                                            &quot;required&quot;:false
                                        },
                                        {
                                            &quot;id&quot;:&quot;module_view&quot;,
                                            &quot;required&quot;:false
                                        },
                                        {
                                            &quot;id&quot;:&quot;host_create&quot;,
                                            &quot;required&quot;:false
                                        }
                                    ],
                                    &quot;sub_resource_types&quot;:[
                                        {
                                            &quot;id&quot;:&quot;host&quot;,
                                            &quot;actions&quot;:[
                                                {
                                                    &quot;id&quot;:&quot;host_edit&quot;,
                                                    &quot;required&quot;:false
                                                },
                                                {
                                                    &quot;id&quot;:&quot;host_view&quot;,
                                                    &quot;required&quot;:false
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    }
}</code></pre><h1 id="token-api">系统 token 查询 API</h1>
<h3 id="token">查询系统 token</h3>
<p>用于<code>权限中心</code> 调用 <code>接入系统</code> 拉取资源信息相关接口的鉴权</p>
<h4 id="url">URL</h4>
<blockquote>
<p>GET /api/v1/model/systems/{system_id}/token</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
</tbody>
</table>
<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-bash">{
    &quot;code&quot;: 0,
    &quot;data&quot;: {
        &quot;token&quot;: &quot;dk9httsqmq4bbdu7aqq6cqp1az6i8org&quot;
    },
    &quot;message&quot;: &quot;ok&quot;
}</code></pre><h1 id="commonactions-api">常用操作配置 CommonActions API</h1>
<h3 id="_1">参数说明</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">常用操作名称</td>
</tr>
<tr>
<td align="left">name_en</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">常用操作英文名，国际化时切换到英文版本显示</td>
</tr>
<tr>
<td align="left">actions</td>
<td align="left">Array(Object)</td>
<td align="left">是</td>
<td align="left">操作列表</td>
</tr>
</tbody>
</table>
<h3 id="1">1. 注册或更新 常用操作</h3>
<h4 id="url">URL</h4>
<p>注册</p>
<blockquote>
<p>POST /api/v1/model/systems/{system_id}/configs/common_actions</p>
</blockquote>
<p>更新 (整个列表完全覆盖更新)</p>
<blockquote>
<p>PUT /api/v1/model/systems/{system_id}/configs/common_actions</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<pre class="codehilite"><code class="language-json">[
    {
        &quot;name&quot;: &quot;测试&quot;,
        &quot;name_en&quot;: &quot;test&quot;,
        &quot;actions&quot;: [
            {
                &quot;id&quot;: &quot;biz_delete&quot;
            }
        ]
    }
]</code></pre>


<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre><h1 id="featureshieldrules-api">功能开关配置 FeatureShieldRules API</h1>
<h3 id="_1">参数说明</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">effect</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">支持黑白名单，值为 deny 或 allow</td>
</tr>
<tr>
<td align="left">feature</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">开启或关闭的功能</td>
</tr>
<tr>
<td align="left">action</td>
<td align="left">Object</td>
<td align="left">是</td>
<td align="left">操作</td>
</tr>
</tbody>
</table>
<p>feature 字段枚举值说明：</p>
<p>| 枚举值 | 说明 |
|:---|:---|:---|
| application.custom_permission.grant | 申请自定义权限 |
| application.custom_permission.renew | 申请自定义权限续期 |
| user_permission.custom_permission.delete | 自定义权限删除 |</p>
<p>action 字段说明：</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">Action 的唯一标识，<code>特别说明:</code> 如果功能是针对整个接入系统，则 id 为 *</td>
</tr>
</tbody>
</table>
<p><code>特别说明</code>：
1. 多条 allow/deny 规则判断最终 effect 的逻辑（类似 Nginx 的 IP 白名单判断），即判断某个功能开启或关闭逻辑：</p>
<pre class="codehilite"><code class="language-bash">在某个功能下的该系统的某个Action的开启与否：allow *[开启] &gt; allow action_id[开启] &gt; deny *[关闭] &gt; deny action_id[关闭] &gt; 默认开启
（1）如果存在allow * 或 allow action_id 的规则匹配，则开启
（3）如果不存在allow * 和 allow action_id 规则，但有deny * 或者deny action_id 规则匹配，则关闭
（4）如果没有任何规则匹配，则默认开启

一般来说，只需要配置屏蔽的功能即可</code></pre>


<ol>
<li>对于依赖操作，如果被屏蔽了，则不会创建依赖操作，比如 edit 依赖 view，但是 view 被屏蔽了，则申请 edit 权限时，不会创建其依赖操作 view</li>
</ol>
<h3 id="1">1. 注册或更新 功能开关规则</h3>
<h4 id="url">URL</h4>
<p>注册</p>
<blockquote>
<p>POST /api/v1/model/systems/{system_id}/configs/feature_shield_rules</p>
</blockquote>
<p>更新 (整个列表完全覆盖更新)</p>
<blockquote>
<p>PUT /api/v1/model/systems/{system_id}/configs/feature_shield_rules</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<pre class="codehilite"><code class="language-json">[
    // 对于自定义申请，屏蔽整个该接入系统所有Action，即该接入系统不支持自定义申请
    {
        &quot;effect&quot;: &quot;deny&quot;,
        &quot;feature&quot;: &quot;application.custom_permission.grant&quot;,
        &quot;action&quot;: {
            &quot;id&quot;: &quot;*&quot;
        }
    },
    // 对于个人权限，接入系统某个Aciton的自定义权限不允许被删除
    {
        &quot;effect&quot;: &quot;deny&quot;,
        &quot;feature&quot;: &quot;user_permission.custom_permission.delete&quot;,
        &quot;action&quot;: {
            &quot;id&quot;: &quot;access_business&quot;
        }
    }
]</code></pre>


<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre><h1 id="resourcecreatoraction-api">新建关联配置 ResourceCreatorAction API</h1>
<h3 id="_1">参数说明</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">config</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">新建关联的配置文件，包含了每种资源类型对应的创建时可以对创建者进行授权的 Action</td>
</tr>
</tbody>
</table>
<p>config 里的每个元素的字段说明:</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型的唯一标识</td>
</tr>
<tr>
<td align="left">actions</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">对应资源被创建时可以对创建者进行授权的 Action 列表</td>
</tr>
<tr>
<td align="left">sub_resource_types</td>
<td align="left">array(object)</td>
<td align="left">否</td>
<td align="left">子资源类型相关可授权的 Action 相关配置信息，列表每个元素同 config 列表里的每个元素一样，这是个递归结构</td>
</tr>
</tbody>
</table>
<p>actions 里的每个元素的字段说明：</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">Action 的唯一标识</td>
</tr>
<tr>
<td align="left">required</td>
<td align="left">bool</td>
<td align="left">是</td>
<td align="left">该 Action 是否是必须的，即后续权限中心支持企业和用户修改创建者赋权时，该 Action 能否不被选择授予</td>
</tr>
</tbody>
</table>
<p><strong><code>required 字段特别说明</code></strong></p>
<blockquote>
<p>假设资源类型 host 产生时可以对 host_edit 、host_view、host_delete 这 3 个权限授权，且 host_delete 配置 required=true</p>
</blockquote>
<ul>
<li>
<p>后续权限中心将支持用户和企业自定义这个新建关联的配置时，host_delete 是必选的，无法去除</p>
</li>
<li>
<p>如果用户自定义新建管理的配置是 host 产生时对 host_view、host_delete 这 2 个权限授权（host_edit 和 host_view 由于 required=false，所以是可以配置为不授权的），那么该用户在接入系统新增 host 后，自动拥有 host_view 和 host_delete</p>
</li>
</ul>
<p><code>注意:</code>
1. 层级结构是依据资源的层级
2. 后续权限中心将会支持这份配置可由企业全局修改和每个用户自定义</p>
<h3 id="1">1. 注册或更新 新建关联配置</h3>
<h4 id="url">URL</h4>
<p>注册</p>
<blockquote>
<p>POST /api/v1/model/systems/{system_id}/configs/resource_creator_actions</p>
</blockquote>
<p>更新 (整个列表完全覆盖更新)</p>
<blockquote>
<p>PUT /api/v1/model/systems/{system_id}/configs/resource_creator_actions</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<ul>
<li>[样例] cmdb 可能的新建关联配置</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;config&quot;:[
        {
            &quot;id&quot;:&quot;biz&quot;,
            &quot;actions&quot;:[
                {
                    &quot;id&quot;:&quot;biz_edit&quot;,
                    &quot;required&quot;:false
                },
                {
                    &quot;id&quot;:&quot;biz_view&quot;,
                    &quot;required&quot;:true
                },
                {
                    &quot;id&quot;:&quot;set_create&quot;,
                    &quot;required&quot;:false
                }
            ],
            &quot;sub_resource_types&quot;:[
                {
                    &quot;id&quot;:&quot;set&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;set_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;set_view&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;module_create&quot;,
                            &quot;required&quot;:false
                        }
                    ],
                    &quot;sub_resource_types&quot;:[
                        {
                            &quot;id&quot;:&quot;module&quot;,
                            &quot;actions&quot;:[
                                {
                                    &quot;id&quot;:&quot;module_edit&quot;,
                                    &quot;required&quot;:false
                                },
                                {
                                    &quot;id&quot;:&quot;module_view&quot;,
                                    &quot;required&quot;:false
                                },
                                {
                                    &quot;id&quot;:&quot;host_create&quot;,
                                    &quot;required&quot;:false
                                }
                            ],
                            &quot;sub_resource_types&quot;:[
                                {
                                    &quot;id&quot;:&quot;host&quot;,
                                    &quot;actions&quot;:[
                                        {
                                            &quot;id&quot;:&quot;host_edit&quot;,
                                            &quot;required&quot;:false
                                        },
                                        {
                                            &quot;id&quot;:&quot;host_view&quot;,
                                            &quot;required&quot;:false
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}</code></pre>


<ul>
<li>[样例] 标准运维新建关联配置</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;config&quot;:[
        {
            &quot;id&quot;:&quot;project&quot;,
            &quot;actions&quot;:[
                {
                    &quot;id&quot;:&quot;project_fast_create_task&quot;,
                    &quot;required&quot;:false
                },
                {
                    &quot;id&quot;:&quot;flow_create&quot;,
                    &quot;required&quot;:false
                },
                {
                    &quot;id&quot;:&quot;project_edit&quot;,
                    &quot;required&quot;:false
                },
                {
                    &quot;id&quot;:&quot;project_view&quot;,
                    &quot;required&quot;:false
                }
            ],
            &quot;sub_resource_types&quot;:[
                {
                    &quot;id&quot;:&quot;common_flow&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;common_flow_view&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;common_flow_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;common_flow_delete&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                },
                {
                    &quot;id&quot;:&quot;flow&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;flow_create_periodic_task&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_create_mini_app&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_create_task&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_delete&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;flow_view&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                },
                {
                    &quot;id&quot;:&quot;mini_app&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;mini_app_create_task&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;mini_app_delete&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;mini_app_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;mini_app_view&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                },
                {
                    &quot;id&quot;:&quot;periodic_task&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;periodic_task_view&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;periodic_task_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;periodic_task_delete&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                },
                {
                    &quot;id&quot;:&quot;task&quot;,
                    &quot;actions&quot;:[
                        {
                            &quot;id&quot;:&quot;task_view&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_edit&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_operate&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_claim&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_delete&quot;,
                            &quot;required&quot;:false
                        },
                        {
                            &quot;id&quot;:&quot;task_clone&quot;,
                            &quot;required&quot;:false
                        }
                    ]
                }
            ]
        }
    ]
}</code></pre>


<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {}
}</code></pre><h1 id="_1">名词及概念说明</h1>
<h2 id="1-resource">1. 资源实例 Resource</h2>
<ul>
<li>id：资源实例唯一标识，<code>需要保证对于一个系统同一种资源类型下id唯一</code></li>
<li>type: 资源类型的 ID，比如主机、集群、业务即 host、set、biz</li>
<li>name: 资源实例名称，比如 192.168.1.1</li>
<li>display_name: 资源实例展示名称，比如 大区 1(qq 大区)</li>
</ul>
<h2 id="2">2. 可用于配置权限的<code>属性</code>和<code>属性值</code></h2>
<p>可以使用资源属性配置权限, 例如用户 1 可以操作所有<code>os=linux</code>的主机;</p>
<p>为了实现这个功能, 需要从接入系统拉取可以配置权限的属性及属性值列表;</p>
<p>比如：在配置平台中，<code>主机</code>有属性<code>地区</code>，属性值, 枚举: 中国、美国、新加坡、日本等，则：</p>
<pre class="codehilite"><code class="language-bash">属性 id = &quot;area&quot;
属性 display_name = &quot;地区&quot;
属性值 id = &quot;China&quot;
属性值  display_name = &quot;中国&quot;</code></pre>


<p>属性值 id 的类型支持 <code>string/int/bool</code>; 以配置平台主机属性为例：</p>
<pre class="codehilite"><code class="language-json">[string]
属性 id = &quot;os&quot;
属性 display_name = &quot;操作系统&quot;
属性值 id = &quot;linux&quot; 
属性值 display_name = &quot;Linux&quot; 

[int]
属性 id = &quot;isp&quot;
属性 display_name = &quot;运营商&quot;
属性值 id = 1 
属性值 display_name = &quot;中国电信&quot;

[bool]
属性 id = &quot;is_public&quot;
属性 display_name = &quot;是否公共&quot;
属性值 id = true
属性值 display_name = &quot;是&quot; </code></pre>


<h2 id="3-path">3. 特殊属性：路径(path)属性说明</h2>
<p><a href="../../../Explanation/04-BkIAMPath.md">说明: 资源拓扑<code>_bk_iam_path_</code></a></p><h1 id="api">资源拉取 API</h1>
<h2 id="api_1">API 地址</h2>
<p>接入系统注册模型到权限中心时
- 注册<code>system</code>有提供<code>system.provider_config.host</code>; 假设为<code>http://cmdb.consul</code>
- 注册<code>resource_type</code>有提供<code>system.provider_config.path</code>; 假设为<code>/api/v1/resources</code></p>
<p>那么权限中心将调用<code>http://cmdb.consul/api/v1/resources</code>去拉取该资源类型相关信息</p>
<p>即: 接入系统需要实现一个 API, 用于权限中心拉取不同资源类型的信息;</p>
<p>需要支持: (一个接口根据参数做分发)
1. list_attr 查询某个资源类型可用于配置权限的属性列表
2. list_attr_value 获取一个资源类型某个属性的值列表
3. list_instance 根据过滤条件查询实例
4. fetch_instance_info 批量获取资源实例详情
5. list_instance_by_policy 根据策略表达式查询资源实例
6. search_instance 搜索资源实例</p>
<hr />
<h2 id="_1">接口协议前置说明</h2>
<p>Request Header: 
- <a href="../01-Overview/03-APIAuth.md">系统间调用接口鉴权:权限中心-&gt;接入系统</a>
- <code>Blueking-Language</code>  国际化多语言，值为：zh-cn 或 en，当值为 en 时，则接口数据返回中包含的 display_name 字段的值为英文，否则默认返回中文；
-  <code>X-Request-Id</code>  请求 request_id, 请记录, 用于错误排查</p>
<p>Response Header:
-  <code>X-Request-Id</code>  将请求 Header 头里的 request_id 返回, 用于错误排查</p>
<p>Response Body: 
遵循蓝鲸官方 API 协议进行返回, <code>code != 0</code> 表示出错, <code>message</code>包含具体信息</p>
<pre class="codehilite"><code class="language-bash">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {
    }
}</code></pre>


<p><strong>重要</strong>: 接入系统 API 都需要返回一个<code>request_id</code>, 权限中心将会在日志中记录, 以便后续联调及正式环境中进行问题排查; </p>
<hr />
<h2 id="_2">协议</h2>
<ul>
<li>Method: <code>POST</code> (注意, 是<code>POST</code>)</li>
<li>Path: <code>system.provider_config.host</code> + <code>system.provider_config.path</code></li>
<li>Request.Body:</li>
</ul>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">对应查询的资源类型</td>
</tr>
<tr>
<td align="left">method</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">需要查询资源信息的方式，不同方式对应查询资源的不同信息，目前值有：<a href="./10-list_attr.md">list_attr</a>、<a href="./11-list_attr_value.md">list_attr_value</a>、 <a href="./12-list_instance.md">list_instance</a>、<a href="./13-fetch_instance_info.md">fetch_instance_info</a>、<a href="./14-list_instance_by_policy.md">list_instance_by_policy</a>、<a href="./15-search_instance.md">search_instance</a>，具体每个值的协议请往下看</td>
</tr>
<tr>
<td align="left">filter</td>
<td align="left">object</td>
<td align="left">否</td>
<td align="left">根据不同查询方式(method)，传入不同的过滤参数</td>
</tr>
<tr>
<td align="left">page</td>
<td align="left">object</td>
<td align="left">否</td>
<td 0="0" 10_="10," _offset_:="&quot;offset&quot;:" align="left" limit:="limit:">当返回数据需要支持分页时，需要参数，具体包含 limit 和 offset 字段，其值类型为 int，比如 </td>
</tr>
</tbody>
</table>
<ul>
<li>Response.Body: </li>
</ul>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">code</td>
<td align="left">int</td>
<td align="left">是</td>
<td align="left">表示请求是否成功，0 表示成功，<code>code != 0</code> 表示出错</td>
</tr>
<tr>
<td align="left">message</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">code != 0 时，message 表示错误信息，code=0 时 可返回 ok 或空字符串</td>
</tr>
<tr>
<td align="left">data</td>
<td align="left">object/array</td>
<td align="left">是</td>
<td align="left">根据不同查询方式(method)，返回的内容也不一样，类型可为数组或者字典</td>
</tr>
</tbody>
</table>
<ul>
<li>code 字段特别说明：</li>
</ul>
<table>
<thead>
<tr>
<th align="left">值</th>
<th align="left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>code = 401</code></td>
<td align="left">代表接口认证失败</td>
</tr>
<tr>
<td align="left"><code>code = 404</code></td>
<td align="left">代表查询的 type(资源类型)或 method(查询资源信息的方式) 不存在，或其他不存在的返回，message 为具体错误信息</td>
</tr>
<tr>
<td align="left"><code>code = 500</code></td>
<td align="left">代表查询时出现系统错误或异常，message 为具体错误或异常信息</td>
</tr>
<tr>
<td align="left"><code>code = 422</code></td>
<td align="left">代表查询时，特别是有过滤搜索时，扫描的资源内容过多，拒绝返回数据</td>
</tr>
<tr>
<td align="left"><code>code = 406</code></td>
<td align="left">代表搜索时 keyword 不符合要求</td>
</tr>
<tr>
<td align="left"><code>code = 429</code></td>
<td align="left">代表接口请求超过接入系统的频率控制</td>
</tr>
</tbody>
</table>
<ul>
<li>说明<ul>
<li>接口只提供给 iam 使用, 需要单独 url/鉴权/逻辑等, 避免同现有业务使用 api 重复</li>
<li>上面的 URL 只是一个示例, 可自行定义, 注册到权限中心即可</li>
<li>需要支持版本, url 格式如<code>/api/v1/</code>, 确保后续可以进行 api 升级</li>
<li>性能要求: </li>
</ul>
</li>
</ul>
<pre class="codehilite"><code class="language-bash">[list_attr] 
&lt; 50ms

[list_attr_value]
无keyword搜索和id过滤条件 &lt; 50ms
keyword搜索 &lt; 100ms
批量 id 过滤（id数量小于10个）&lt; 100ms
批量 id 过滤（id数量大于10个）&lt; 200ms

[list_instance]
按照资源的上级过滤查询 &lt; 50ms

[fetch_instance_info] 性能敏感，由于用于鉴权，所以必须严格保证该接口性能
单个资源获取 &lt; 20ms
批量资源获取 &lt; 100ms

[list_instance_by_policy]
&lt; 500ms

[search_instance]
按照资源实例进行keyword搜索查询 &lt; 100ms</code></pre><h1 id="list_attr">list_attr</h1>
<h2 id="list_attr_1">list_attr 查询某个资源类型可用于配置权限的属性列表</h2>
<blockquote>
<p>在权限中心里用于（1）<code>产品</code>上按照属性配置权限（2）<code>产品</code>上回显权限</p>
</blockquote>
<p>比如: 在配置平台中，主机的可用于配置权限的属性列表：os(操作系统)/country(国家)/province(省份)/isp(运营商) 等</p>
<h3 id="requestbody">Request.Body</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">对应查询的资源类型(ResourceType)</td>
</tr>
<tr>
<td align="left">method</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">值为：list_attr</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;list_attr&quot;
}</code></pre>


<h3 id="responsebody">Response.Body</h3>
<p>data 字段，类型为 Array</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源属性的唯一标识</td>
</tr>
<tr>
<td align="left">display_name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源属性的展示名称</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: [
        {&quot;id&quot;: &quot;os&quot;, &quot;display_name&quot;: &quot;操作系统&quot;},
        {&quot;id&quot;: &quot;country&quot;, &quot;display_name&quot;: &quot;国家&quot;},
        {&quot;id&quot;: &quot;province&quot;, &quot;display_name&quot;: &quot;省份&quot;},
        {&quot;id&quot;: &quot;isp&quot;, &quot;display_name&quot;: &quot;运营商&quot;}
    ]
}</code></pre><h1 id="list_attr_value">list_attr_value</h1>
<h2 id="list_attr_value_1">list_attr_value 获取一个资源类型某个属性的值列表</h2>
<blockquote>
<p>可用于配置权限的属性 的值列表</p>
<p>在权限中心产品里用于（1）<code>产品</code>上按照属性配置权限（2）<code>产品</code>上回显权限</p>
</blockquote>
<p>比如: 在配置平台中，主机(host)资源的操作系统属性(os)可用于配置权限，对应的操作系统属性的值列表：linux(Linux)、windows(Windows)、mac(Mac)</p>
<h3 id="_1">需支持的过滤查询</h3>
<ul>
<li>keyword 搜索<ul>
<li>接入系统获取到 keyword 后，可选择 id 或 display_name 进行模糊搜索过滤，模糊搜索规则可以是前缀匹配或包含子串等其他匹配规则</li>
</ul>
</li>
<li>批量 id 过滤</li>
</ul>
<p>简单例子：
【keyword 搜索】</p>
<pre class="codehilite"><code class="language-json">&quot;filter&quot;: {
    &quot;attr&quot;: &quot;os&quot;,
    &quot;keyword&quot;: &quot;Li&quot; 
}</code></pre>


<p>【批量 id 过滤】</p>
<pre class="codehilite"><code class="language-json">&quot;filter&quot;: {
    &quot;attr&quot;: &quot;os&quot;,
    &quot;ids&quot;: [&quot;linux&quot;, &quot;windows&quot;]
}</code></pre>


<h3 id="requestbody">Request.Body</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">对应查询的资源类型</td>
</tr>
<tr>
<td align="left">method</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">值为：list_attr_value</td>
</tr>
<tr>
<td align="left">filter</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">根据 2.1 里需支持的过滤查询，传入不同的参数</td>
</tr>
<tr>
<td align="left">page</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">返回数据需要支持分页，该参数必填，具体说明请查看 <a href="./01-API.md">需实现接口的基础协议里的 Request.Body.page 字段</a>, <code>limit 最大为1000</code></td>
</tr>
</tbody>
</table>
<p>filter 字段</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">attr</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">需要查询的资源属性 id</td>
</tr>
<tr>
<td align="left">keyword</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">资源属性值的搜索关键字</td>
</tr>
<tr>
<td align="left">ids</td>
<td align="left">Array(string/int/bool)</td>
<td align="left">否</td>
<td align="left">资源属性值 ID 列表, <a href="./00-Concepts.md">值的数据类型详细说明</a></td>
</tr>
</tbody>
</table>
<ul>
<li>无过滤条件</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;list_attr_value&quot;,
    &quot;filter&quot;: {
        &quot;attr&quot;: &quot;os&quot;
    },
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }
}</code></pre>


<ul>
<li>有过滤条件</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;list_attr_value&quot;,
    &quot;filter&quot;: {
        &quot;attr&quot;: &quot;os&quot;,
        &quot;keyword&quot;: &quot;Li&quot;
    },
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }
}</code></pre>


<h3 id="responsebody">Response.Body</h3>
<p>data 字段，类型为 Dict</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">count</td>
<td align="left">int</td>
<td align="left">是</td>
<td align="left">查询到的总数量</td>
</tr>
<tr>
<td align="left">results</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">对应的属性值列表</td>
</tr>
</tbody>
</table>
<p>results 字段，类型 Array</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string/int/bool</td>
<td align="left">是</td>
<td align="left">资源属性值的唯一标识, <a href="./00-Concepts.md">值的数据类型详细说明</a></td>
</tr>
<tr>
<td align="left">display_name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源属性值的展示名称</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {
        &quot;count&quot;: 100,
        &quot;results&quot;: [
            {&quot;id&quot;: &quot;linux&quot;, &quot;display_name&quot;: &quot;Linux&quot;},
            {&quot;id&quot;: &quot;windows&quot;, &quot;display_name&quot;: &quot;Windows&quot;},
            {&quot;id&quot;: &quot;mac&quot;, &quot;display_name&quot;: &quot;Mac&quot;}
        ]
    }
}</code></pre><h1 id="list_instance">list_instance</h1>
<h2 id="list_instance_1">list_instance 根据过滤条件查询实例</h2>
<blockquote>
<p>在权限中心里用于（1）<code>产品</code>上按照资源拓扑树选择资源实例</p>
</blockquote>
<h3 id="_1">需支持的过滤查询</h3>
<ul>
<li>按照资源的上级过滤查询</li>
</ul>
<p>简单例子：</p>
<p>【按照资源的上级过滤查询】</p>
<pre class="codehilite"><code class="language-json">&quot;filter&quot;: {
    &quot;parent&quot;: {
        &quot;type&quot;: &quot;module&quot;,
        &quot;id&quot;: &quot;m1&quot;
    }
}</code></pre>


<h3 id="requestbody">Request.Body</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">对应查询的资源类型</td>
</tr>
<tr>
<td align="left">method</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">值为：list_instance</td>
</tr>
<tr>
<td align="left">filter</td>
<td align="left">object</td>
<td align="left">否</td>
<td align="left">根据 3.1 里需支持的过滤查询，传入不同的参数</td>
</tr>
<tr>
<td align="left">page</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">返回数据需要支持分页，该参数必填，具体说明请查看 <a href="./01-API.md">需实现接口的基础协议里的 Request.Body.page 字段</a>, <code>limit 最大为1000</code></td>
</tr>
</tbody>
</table>
<p>filter 字段</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">parent</td>
<td align="left">object</td>
<td align="left">否</td>
<td align="left">资源的直接上级，具体包含 type 和 id，type 为直接上级资源的类型，id 为直接上级资源实例 ID</td>
</tr>
</tbody>
</table>
<ul>
<li>无条件查询</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;list_instance&quot;,
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }
}</code></pre>


<ul>
<li>上级过滤查询</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;list_instance&quot;,
    &quot;filter&quot;: {
        &quot;parent&quot;: {
            &quot;type&quot;: &quot;module&quot;,
            &quot;id&quot;: &quot;m1&quot;
        }
    },
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }
}</code></pre>


<h3 id="responsebody">Response.Body</h3>
<p>data 字段，类型为 Dict</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">count</td>
<td align="left">int</td>
<td align="left">是</td>
<td align="left">查询到的资源实例的总数量</td>
</tr>
<tr>
<td align="left">results</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">对应的资源实例列表</td>
</tr>
</tbody>
</table>
<p>results 字段 ，类型 Array</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的唯一标识</td>
</tr>
<tr>
<td align="left">display_name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的展示名称</td>
</tr>
<tr>
<td align="left">child_type</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">非必填，仅仅"用户管理"系统定制的字段，其他系统不需要返回，表示该资源实例的下一层资源类型，仅仅用于动态资源层级，且其下一层与本层类型一致的情况，空值表示已经无下一层级，该数据将用于在权限中心产品拉取同一资源动态层级拓扑</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {
        &quot;count&quot;: 100,
        &quot;results&quot;: [
            {&quot;id&quot;: &quot;h1&quot;, &quot;display_name&quot;: &quot;192.168.1.1&quot;},
            {&quot;id&quot;: &quot;h2&quot;, &quot;display_name&quot;: &quot;192.168.1.2&quot;},
            {&quot;id&quot;: &quot;h3&quot;, &quot;display_name&quot;: &quot;192.168.1.3&quot;}
        ]
    }
}</code></pre><h1 id="fetch_instance_info">fetch_instance_info</h1>
<h2 id="fetch_instance_info_1">fetch_instance_info 批量获取资源实例详情</h2>
<blockquote>
<p>在权限中心里用于（1）<code>产品</code>上回显权限（2）<code>鉴权</code>上依赖资源的查询</p>
</blockquote>
<h3 id="_1">需支持的查询</h3>
<ul>
<li>批量属性 attr 列表</li>
</ul>
<p>简单例子：</p>
<p>【批量属性 attr 列表】</p>
<p>比如查询主机 h1 和主机 h2 的 路径(path)、名称(name)、操作系统(os)和所属国家(country)</p>
<pre class="codehilite"><code class="language-json">&quot;filter&quot;: {
    &quot;ids&quot;: [&quot;h1&quot;, &quot;h2&quot;],  // 资源实例ID
    &quot;attrs&quot;: [&quot;_bk_iam_path_&quot;, &quot;display_name&quot;, &quot;os&quot;, &quot;country&quot;] // 属性列表
}</code></pre>


<h3 id="requestbody">Request.Body</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">对应查询的资源类型</td>
</tr>
<tr>
<td align="left">method</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">值为：fetch_instance_info</td>
</tr>
<tr>
<td align="left">filter</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">根据需支持的查询，传入不同的参数</td>
</tr>
</tbody>
</table>
<p>filter 字段:</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">ids</td>
<td align="left">array(string)</td>
<td align="left">是</td>
<td align="left">需要查询的资源实例的唯一标识列表, <code>最多1000个</code></td>
</tr>
<tr>
<td align="left">attrs</td>
<td align="left">array(string)</td>
<td align="left">否</td>
<td align="left">需要查询的资源属性列表，比如["<em>bk_iam_path</em>", "os"]，空列表或无该参数则表示查询所有属性</td>
</tr>
</tbody>
</table>
<ul>
<li>无查询条件，表示查询资源的所有属性</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;fetch_instance_info&quot;,
    &quot;filter&quot;: {
        &quot;ids&quot;: [&quot;h1&quot;, &quot;h2&quot;]
    }
}</code></pre>


<ul>
<li>有过滤条件</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;fetch_instance_info&quot;,
    &quot;filter&quot;: {
        &quot;ids&quot;: [&quot;h1&quot;, &quot;h2&quot;],
        &quot;attrs&quot;: [&quot;_bk_iam_path_&quot;, &quot;os&quot;, &quot;country&quot;]
    }
}</code></pre>


<h3 id="responsebody">Response.Body</h3>
<p>data 字段，类型为 Array</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的唯一标识</td>
</tr>
<tr>
<td align="left"><code>&lt;attr&gt;</code></td>
<td align="left">string/int/bool 或 array(string/int/bool)</td>
<td align="left">是</td>
<td align="left">根据查询条件中的 attrs 返回，无 attrs 参数则返回所有属性</td>
</tr>
</tbody>
</table>
<p><code>特殊属性</code>:</p>
<ul>
<li><a href="../../../Explanation/04-BkIAMPath.md">说明: 资源拓扑<code>_bk_iam_path_</code></a></li>
<li><a href="../../../Explanation/08-BkIAMApprover.md">说明: 资源审批人<code>_bk_iam_approver_</code></a></li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: [
        {
            &quot;id&quot;: &quot;h1&quot;,
            &quot;os&quot;: &quot;Linux&quot;,
            &quot;country&quot;: &quot;China&quot;,
            &quot;isp&quot;: 1,
            &quot;is_public&quot;: true,
            &quot;_bk_iam_path_&quot;: [
                &quot;/biz,1/set,1/module,1/&quot;,
                &quot;/biz,1/set,1/module,2/&quot;
            ]
        },
        {
            &quot;id&quot;: &quot;h2&quot;,
            &quot;os&quot;: &quot;Windows&quot;,
            &quot;country&quot;: &quot;China&quot;,
            &quot;isp&quot;: 3,
            &quot;is_public&quot;: false,
            &quot;_bk_iam_path_&quot;: [
                &quot;/biz,1/set,1/module,1/&quot;,
                &quot;/biz_set,1/set,2/module,2/&quot;
            ]
        }
    ]
}</code></pre><h1 id="list_instance_by_policy">list_instance_by_policy</h1>
<h2 id="list_instance_by_policy_1">list_instance_by_policy 根据策略表达式查询资源实例</h2>
<blockquote>
<p>在权限中心里用于（1）<code>产品</code>上动态查询资源实例进行预览</p>
</blockquote>
<h3 id="requestbody">Request.Body</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">对应查询的资源类型</td>
</tr>
<tr>
<td align="left">method</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">值为：list_instance_by_policy</td>
</tr>
<tr>
<td align="left">filter</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">查询条件</td>
</tr>
<tr>
<td align="left">page</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">返回数据需要支持分页，该参数必填，具体说明请查看 <a href="./01-API.md">需实现接口的基础协议里的 Request.Body.page 字段</a></td>
</tr>
</tbody>
</table>
<p>filter 字段</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">expression</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">资源的表达式，<a href="../../Expression/01-Schema.md">协议请查看</a></td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;list_instance_by_policy&quot;,
    &quot;filter&quot;: {
        &quot;expression&quot;: {
            &quot;op&quot;: &quot;OR&quot;,
            &quot;content&quot;: [
            {
                &quot;op&quot;: &quot;in&quot;,
                &quot;field&quot;: &quot;host.id&quot;,
                &quot;value&quot;: [1, 2, 3]
            },
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;host.os&quot;,
                &quot;value&quot;: &quot;linux&quot;
            },
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;host.owner&quot;,
                &quot;value&quot;: &quot;admin&quot;
            },
            {
                &quot;op&quot;: &quot;OR&quot;,
                &quot;content&quot;: [
                {
                    &quot;op&quot;: &quot;starts_with&quot;,
                    &quot;field&quot;: &quot;host._bk_iam_path_&quot;,
                    &quot;value&quot;: &quot;/biz,1/&quot;
                },
                {
                    &quot;op&quot;: &quot;starts_with&quot;,
                    &quot;field&quot;: &quot;host._bk_iam_path_&quot;,
                    &quot;value&quot;: &quot;/biz,2/&quot;
                }]
            },
            {
                &quot;op&quot;: &quot;AND&quot;,
                &quot;content&quot;: [
                {
                    &quot;op&quot;: &quot;eq&quot;,
                    &quot;field&quot;: &quot;host.biz&quot;,
                    &quot;value&quot;: &quot;bk&quot;
                },
                {
                    &quot;op&quot;: &quot;eq&quot;,
                    &quot;field&quot;: &quot;host.status&quot;,
                    &quot;value&quot;: &quot;online&quot;
                }]
            }]
        }
    },
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }    
}</code></pre>


<h3 id="responsebody">Response.Body</h3>
<p>data 字段，类型为 Dict</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">count</td>
<td align="left">int</td>
<td align="left">是</td>
<td align="left">查询到的资源实例的总数量</td>
</tr>
<tr>
<td align="left">results</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">对应到的资源实例列表</td>
</tr>
</tbody>
</table>
<p>results 字段 ，类型 Array</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的唯一标识</td>
</tr>
<tr>
<td align="left">display_name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的展示名称</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {
        &quot;count&quot;: 100,
        &quot;results&quot;: [
            {&quot;id&quot;: &quot;h1&quot;, &quot;display_name&quot;: &quot;192.168.1.1&quot;},
            {&quot;id&quot;: &quot;h2&quot;, &quot;display_name&quot;: &quot;192.168.1.2&quot;},
            {&quot;id&quot;: &quot;h3&quot;, &quot;display_name&quot;: &quot;192.168.1.3&quot;}
        ]
    }
}</code></pre><h1 id="search_instance">search_instance</h1>
<h2 id="search_instance_1">search_instance 根据过滤条件和搜索关键字查询实例</h2>
<blockquote>
<p>在权限中心里用于（1）<code>产品</code>上搜索资源实例（1）<code>产品</code>上支持拓扑树的资源搜索</p>
</blockquote>
<h3 id="_1">需支持的过滤查询</h3>
<ul>
<li>按照资源实例进行 Keyword 搜索查询<ul>
<li>接入系统获取到 keyword 后，可支持对应资源实例的唯一标识 id、名称 name、展示名称 display_name 等字段进行模糊搜索过滤，<code>默认必须支持display_name搜索</code>，搜索结果为<code>包含关键词</code>。</li>
</ul>
</li>
<li>按照资源的上级 + 资源实例 Keyword 搜索 查询</li>
</ul>
<p><strong>重要</strong>：
<code>搜索不要区分大小写！！！</code>
<code>搜索不要区分大小写！！！</code>
<code>搜索不要区分大小写！！！</code></p>
<p>简单例子：</p>
<p>【按照资源实例进行 Keyword 搜索查询】</p>
<pre class="codehilite"><code class="language-json">&quot;filter&quot;: {
    &quot;keyword&quot;: &quot;192.168.&quot;
}</code></pre>


<p>【按照资源的上级 + 资源实例 Keyword 搜索 查询】</p>
<pre class="codehilite"><code class="language-json">&quot;filter&quot;: {
    &quot;parent&quot;: {
        &quot;type&quot;: &quot;module&quot;,
        &quot;id&quot;: &quot;m1&quot;
    },
    &quot;keyword&quot;: &quot;192.168.&quot;
}</code></pre>


<p><strong><code>特别注意</code></strong>
由于 keyword 搜索可能性能很低，接入系统需要做<code>频率控制</code>和实现适当的<code>缓存机制</code>，否则可能会引发接入系统负载过高而导致正常业务服务的故障</p>
<h3 id="requestbody">Request.Body</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">对应查询的资源类型</td>
</tr>
<tr>
<td align="left">method</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">值为：search_instance</td>
</tr>
<tr>
<td align="left">filter</td>
<td align="left">object</td>
<td align="left">否</td>
<td align="left">根据 6.1 里需支持的过滤查询，传入不同的参数</td>
</tr>
<tr>
<td align="left">page</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">返回数据需要支持分页，该参数必填，具体说明请查看 <a href="./01-API.md">需实现接口的基础协议里的 Request.Body.page 字段</a>, <code>limit 最大为1000</code></td>
</tr>
</tbody>
</table>
<p>filter 字段</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">keyword</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">资源实例的搜索关键字</td>
</tr>
<tr>
<td align="left">parent</td>
<td align="left">object</td>
<td align="left">否</td>
<td align="left">资源的直接上级，具体包含 type 和 id，type 为直接上级资源的类型，id 为直接上级资源实例 ID  <code>两种情况下可为空，(1) 本身资源类型无上级 (2) 权限中心产品上只需要根据Keyword全局搜索该资源类型，可能场景如某种资源类型的下拉框过滤选择</code></td>
</tr>
</tbody>
</table>
<ul>
<li>Keyword 搜索查询</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;search_instance&quot;,
    &quot;filter&quot;: {
        &quot;keyword&quot;: &quot;192.168.&quot;
    },
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }
}</code></pre>


<ul>
<li>上级+Keyword 搜索查询</li>
</ul>
<pre class="codehilite"><code class="language-bash">{
    &quot;type&quot;: &quot;host&quot;,
    &quot;method&quot;: &quot;search_instance&quot;,
    &quot;filter&quot;: {
       &quot;parent&quot;: {
            &quot;type&quot;: &quot;module&quot;,
            &quot;id&quot;: &quot;m1&quot;
        }
        &quot;keyword&quot;: &quot;192.168.&quot;
    },
    &quot;page&quot;: {
        &quot;offset&quot;: 0,
        &quot;limit&quot;: 20
    }
}</code></pre>


<h3 id="responsebody">Response.Body</h3>
<p>code 字段说明
- <code>code = 422</code> 代表 Keyword 搜索时，扫描的资源内容过多，无法支持，拒绝返回数据，对于 IAM 产品上将提示用户完善搜索条件再搜索
- <code>code = 429</code> 代表接口超过接入系统的频率控制 </p>
<p>data 字段，类型为 Dict</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">count</td>
<td align="left">int</td>
<td align="left">是</td>
<td align="left">查询到的资源实例的总数量</td>
</tr>
<tr>
<td align="left">results</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">对应的资源实例列表</td>
</tr>
</tbody>
</table>
<p>results 字段 ，类型 Array</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的唯一标识</td>
</tr>
<tr>
<td align="left">display_name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的展示名称</td>
</tr>
<tr>
<td align="left">child_type</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">非必填，仅仅"用户管理"系统定制的字段，其他系统不需要返回，表示该资源实例的下一层资源类型，仅仅用于动态资源层级，且其下一层与本层类型一致的情况，空值表示已经无下一层级，该数据将用于在权限中心产品拉取同一资源动态层级拓扑</td>
</tr>
</tbody>
</table>
<ul>
<li>正常查询返回</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;&quot;,
    &quot;data&quot;: {
        &quot;count&quot;: 100,
        &quot;results&quot;: [
            {&quot;id&quot;: &quot;h1&quot;, &quot;display_name&quot;: &quot;192.168.1.1&quot;},
            {&quot;id&quot;: &quot;h2&quot;, &quot;display_name&quot;: &quot;192.168.1.2&quot;},
            {&quot;id&quot;: &quot;h3&quot;, &quot;display_name&quot;: &quot;192.168.1.3&quot;}
        ]
    }
}</code></pre>


<ul>
<li>搜到的 Keyword 不满足要求，即 keyword 的参数校验规则，比如，可能对于某些资源类型，keyword 至少 2 个字符才进行搜索<ul>
<li><code>对于message字段，必须清楚提示keyword的校验规则</code></li>
</ul>
</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 406,
    &quot;message&quot;: &quot;the length of keyword should be greater than or equals to 2&quot;,
    &quot;data&quot;: {}
}</code></pre>


<ul>
<li>搜索结果分页返回，如果个别资源类型因为搜索结果过多而导致性能问题，无法返回时，</li>
<li><code>对于这种情况，权限中心产品上将会提示用户完善Keyword，尽量精确</code></li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 422,
    &quot;message&quot;: &quot;not support, too much data found&quot;,
    &quot;data&quot;: {}
}</code></pre>


<ul>
<li>接口超过调用频率控制</li>
</ul>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 429,
    &quot;message&quot;: &quot;exceed api rate limiting&quot;,
    &quot;data&quot;: {}
}</code></pre><h1 id="sdk-api">SDK 鉴权 API</h1>
<h2 id="_1">说明</h2>
<p>重要:</p>
<ol>
<li>不存在跨系统资源依赖
        - 那么请求中可以不带 resources，此时会返回 用户 在 这个系统 的这个操作 的所有策略，然后在本地进行计算;<ul>
<li>所以不存在跨系统资源依赖，可以做批量接口，一次策略查询，然后遍历本地的多个资源，逐一计算结果 (此时少了 N-1 次 IO 查询)</li>
</ul>
</li>
<li>如果存在跨系统资源依赖<ul>
<li>请求策略查询，一定要带上跨系统依赖资源，上面的示例，一定要带上 bk_cmdb; 因为权限中心需要到被依赖系统拉取相关的内容进行计算</li>
<li>所以存在跨系统资源依赖，不能做批量接口; 除非本地的多个资源依赖的是同一个其他系统资源，例如 10 个 job 作业依赖的同一个 cmdb 主机，要鉴权</li>
</ul>
</li>
<li>如果传了 resources<ul>
<li>会走两阶段计算</li>
<li>权限中心会拿 requests 中传递的资源，先行进行计算，得到中间结果(也是策略)，返回给接入系统，接入系统继续计算</li>
</ul>
</li>
</ol>
<h2 id="1-policy-query">1. policy query 拉取权限策略</h2>
<p>sdk 接入, 需要实现</p>
<ol>
<li>鉴权: 拉取权限策略</li>
<li>获取有权限的资源列表</li>
</ol>
<p>两个将使用同一个接口, 从服务端拉取策略列表</p>
<p>返回结果中包含条件表达式. 具体见<a href="../../../Reference/Expression/01-Schema.md">条件表达式协议</a></p>
<h3 id="11-url">1.1 URL</h3>
<blockquote>
<p>POST /api/v1/policy/query</p>
</blockquote>
<h3 id="12-request">1.2 Request</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">系统唯一标识</td>
</tr>
<tr>
<td align="left">subject</td>
<td align="left">subject</td>
<td align="left">是</td>
<td align="left">鉴权实体</td>
</tr>
<tr>
<td align="left">action</td>
<td align="left">action</td>
<td align="left">是</td>
<td align="left">操作</td>
</tr>
<tr>
<td align="left">resources</td>
<td align="left">Array(resource_node)</td>
<td align="left">是</td>
<td align="left">资源实例, 资源类型的顺序必须操作注册时的顺序一致;可以为空列表</td>
</tr>
</tbody>
</table>
<p>action</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">操作 ID</td>
</tr>
</tbody>
</table>
<p>subject</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象类型, 当前只支持 user</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象 ID</td>
</tr>
</tbody>
</table>
<p>resource_node</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源系统 ID</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源实例 ID</td>
</tr>
<tr>
<td align="left">attribute</td>
<td align="left">对象</td>
<td align="left">是</td>
<td align="left">资源属性</td>
</tr>
</tbody>
</table>
<h4 id="cmdb">无 cmdb 依赖</h4>
<pre class="codehilite"><code class="language-json"># 1. 
{
    &quot;system&quot;: &quot;bk_job&quot;,
    &quot;subject&quot;:
    {
        &quot;type&quot;: &quot;user&quot;,
        &quot;id&quot;: &quot;admin&quot;
    },
    &quot;action&quot;: {
        &quot;id&quot;: &quot;edit&quot;
    },
    &quot;resources&quot;: []
}</code></pre>


<h4 id="cmdb_1">有 cmdb 依赖</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;system&quot;: &quot;bk_job&quot;,
    &quot;subject&quot;:
    {
        &quot;type&quot;: &quot;user&quot;,
        &quot;id&quot;: &quot;admin&quot;
    },
    &quot;action&quot;: {
        &quot;id&quot;: &quot;execute&quot;
    },
    &quot;resources&quot;: [
    {
        &quot;system&quot;: &quot;bk_cmdb&quot;,
        &quot;type&quot;: &quot;host&quot;,
        &quot;id&quot;: &quot;192.168.1.1&quot;
    }]
}</code></pre>


<h3 id="13-response">1.3 Response</h3>
<blockquote>
<p>Status: 200 OK</p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: {  // 条件表达式
        &quot;field&quot;: &quot;host.id&quot;,
        &quot;op&quot;: &quot;any&quot;,
        &quot;value&quot;: []
    }
}</code></pre>


<h2 id="2-policy-query-by-actions">2. policy query by actions 批量拉取一批操作的权限策略</h2>
<p>场景: 接入系统需要对同一资源类型的一批资源实例的多个操作鉴权, 比如资源实例列表页显示多个操作是否有权限</p>
<p>约束:</p>
<ol>
<li>一批资源的资源类型必须是一样的</li>
<li>action 如果对 cmdb 资源有依赖, 依赖的 cmdb 资源实例必须是同一个</li>
</ol>
<p>SDK 实现:</p>
<ol>
<li>批量拉取一批操作的权限策略</li>
<li>本地遍历计算资源实例是否有权限</li>
</ol>
<h3 id="21-url">2.1 URL</h3>
<blockquote>
<p>POST /api/v1/policy/query_by_actions</p>
</blockquote>
<h3 id="22-request">2.2 Request</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">系统唯一标识</td>
</tr>
<tr>
<td align="left">subject</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">subject</td>
</tr>
<tr>
<td align="left">actions</td>
<td align="left">Array(action)</td>
<td align="left">是</td>
<td align="left">操作列表</td>
</tr>
<tr>
<td align="left">resources</td>
<td align="left">Array(resource_node)</td>
<td align="left">是</td>
<td align="left">资源实例, 资源类型的顺序必须操作注册时的顺序一致</td>
</tr>
</tbody>
</table>
<p>action</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">操作 ID</td>
</tr>
</tbody>
</table>
<p>subject</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象类型, 当前只支持 user</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象 ID</td>
</tr>
</tbody>
</table>
<p>resource_node</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源系统 ID</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源实例 ID</td>
</tr>
<tr>
<td align="left">attribute</td>
<td align="left">对象</td>
<td align="left">是</td>
<td align="left">资源属性</td>
</tr>
</tbody>
</table>
<h4 id="cmdb_2">无 cmdb 依赖</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;system&quot;: &quot;bk_job&quot;,
    &quot;subject&quot;:
    {
        &quot;type&quot;: &quot;user&quot;,
        &quot;id&quot;: &quot;admin&quot;
    },
    &quot;actions&quot;: [
        {
            &quot;id&quot;: &quot;edit&quot;
        },
        {
            &quot;id&quot;: &quot;view&quot;
        }
    ],
    &quot;resources&quot;: []
}</code></pre>


<h4 id="cmdb_3">有 cmdb 依赖</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;system&quot;: &quot;bk_job&quot;,
    &quot;subject&quot;:
    {
        &quot;type&quot;: &quot;user&quot;,
        &quot;id&quot;: &quot;admin&quot;
    },
    &quot;actions&quot;: [
        {
            &quot;id&quot;: &quot;execute&quot;
        },
        {
            &quot;id&quot;: &quot;quick_execute&quot;
        }
    ],
    &quot;resources&quot;: [
    {
        &quot;system&quot;: &quot;bk_cmdb&quot;,
        &quot;type&quot;: &quot;host&quot;,
        &quot;id&quot;: &quot;192.168.1.1&quot;
    }]
}</code></pre>


<h3 id="23-response">2.3 Response</h3>
<blockquote>
<p>Status: 200 OK</p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: [ // action的顺序与请求中的acitons顺序一致
        {
            &quot;action&quot;:{
                &quot;id&quot;:&quot;edit&quot;
            },
            &quot;condition&quot;: {  // 条件表达式
                &quot;field&quot;: &quot;host.id&quot;,
                &quot;op&quot;: &quot;any&quot;,
                &quot;value&quot;: []
            }
        },
        {
            &quot;action&quot;:{
                &quot;id&quot;:&quot;view&quot;
            },
            &quot;condition&quot;: {  // 条件表达式
                &quot;field&quot;: &quot;host.id&quot;,
                &quot;op&quot;: &quot;any&quot;,
                &quot;value&quot;: []
            }
        }
    ]
}</code></pre>


<h2 id="3-query_by_ext_resources">3. query_by_ext_resources 批量第三方依赖鉴权策略查询</h2>
<h3 id="31">3.1 背景</h3>
<p>本系统的操作依赖外部系统资源类型, 需要大批量使用外部资源实例鉴权</p>
<p>例如: 用户在作业平台需要触发上千台主机上批量执行某个作业, 比如 需要在 host1, host2 上执行 job1</p>
<p>这个接口, 支持拉取策略的同时, 帮助接入系统到<code>依赖系统</code>拉取策略计算需要的资源信息; </p>
<p>接入系统同时拿到<code>策略</code>和<code>资源信息</code>, 就可以完成计算, 确认是否有权限;</p>
<p>注: 由于大批量遍历计算 expression 属于 cpu 密集计算, 如果计算放在 IAM, 在并发批量计算时, 会导致 IAM 服务 CPU 资源不足, 进而服务不可用, 所以需要把计算分散到接入系统分布计算, 减轻 IAM 服务的压力</p>
<h4 id="1-1000">场景 1: 外部依赖资源实例的数量<strong>不</strong>超过 1000 个</h4>
<p>使用建议:</p>
<p>直接使用<code>query_by_ext_resources</code>接口查询策略表达式与资源实例相关信息到本地后遍历计算是否有权限</p>
<h4 id="2-1000">场景 2: 外部依赖资源实例的数量<strong>超过</strong>了 1000 个</h4>
<hr />
<p>使用建议:</p>
<ol>
<li>使用<code>policy/query</code>接口查询策略表达式</li>
<li>本地计算表达式中是否有<code>any</code>, 是否有实例<code>id in ["id1", "id2"]</code>初步计算部分外部依赖资源实例是否权限</li>
<li>对于在第二步中计算无权限的资源实例, 再分批次(每次不超过 1000 个)调用<code>query_by_ext_resources</code>接口查询策略表达式与资源实例相关信息到本地后遍历计算是否有权限</li>
</ol>
<h3 id="32">3.2 使用方式</h3>
<ol>
<li>在 request body 中 resources 传 job1 相关的资源信息, 在 ext_resources 中传第三方依赖的 host1, host2</li>
<li>返回的结果中 expression 是过滤了 request 中 resource 相关条件后的条件表达式, 结果的 ext_resources 返回填充属性的资源信息</li>
<li><strong>鉴权计算</strong>: 接入系统拿到 ext_resource 后遍历每个 host 实例带入 expression 中计算得到鉴权结果</li>
</ol>
<p>注意:</p>
<ul>
<li>request 中 resources 与 ext_resources 的关系, 当前 ext_resources 只能有一种第三方依赖类型的实例, resource 必须为 action 依赖的其它资源类型的实例</li>
<li>ext_resources 一次查询不能超过 1000 个, 如果超过建议分批次查询</li>
</ul>
<hr />
<h3 id="33">3.3 协议</h3>
<h4 id="331-url">3.3.1 URL</h4>
<blockquote>
<p>POST /api/v1/policy/query_by_ext_resources</p>
</blockquote>
<h4 id="332-request">3.3.2 Request</h4>
<pre class="codehilite"><code class="language-json">{
  &quot;system&quot;: &quot;bk_job&quot;,
  &quot;subject&quot;: {
    &quot;type&quot;: &quot;user&quot;,
    &quot;id&quot;: &quot;admin&quot;
  },
  &quot;action&quot;: {
    &quot;id&quot;: &quot;execute&quot;
  },
  &quot;resources&quot;: [  # 参与过滤策略的资源实例, 每种资源类型只能传1个, 可以不传, 不传时返回的表达式包含操作关联所有的资源类型的条件
    {
      &quot;system&quot;: &quot;bk_job&quot;,
      &quot;type&quot;: &quot;job&quot;,
      &quot;id&quot;: &quot;job1&quot;,
      &quot;attribute&quot;: {}
    }
  ],
  &quot;ext_resources&quot;: [  # 不参与计算的资源类型, 可以批量传入, IAM会向第三方系统查询资源的属性信息, 一次最多1000个
    {
      &quot;system&quot;: &quot;bk_cmdb&quot;,
      &quot;type&quot;: &quot;host&quot;,
      &quot;ids&quot;: [
        &quot;host1&quot;,
        &quot;host2&quot;
      ]
    }
  ]
}</code></pre>


<h4 id="333-response">3.3.3 Response</h4>
<blockquote>
<p>Status: 200 OK</p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;ok&quot;,
  &quot;data&quot;: {
    &quot;expression&quot;: {  # 已经代入request中resources计算过后的表达式
      &quot;op&quot;: &quot;AND&quot;,
      &quot;content&quot;: [
        {
          &quot;op&quot;: &quot;in&quot;,
          &quot;field&quot;: &quot;host.id&quot;,
          &quot;value&quot;: [
            &quot;host1&quot;,
            &quot;host2&quot;
          ]
        },
        {
          &quot;op&quot;: &quot;starts_with&quot;,
          &quot;field&quot;: &quot;host._bk_iam_path_&quot;,
          &quot;value&quot;: [
            &quot;/biz,5/&quot;
          ]
        }
      ]
    },
    &quot;ext_resources&quot;: [  # 查询得到的第三方资源实例, 填充了与表达式相关的属性
      {
        &quot;system&quot;: &quot;bk_cmdb&quot;,
        &quot;type&quot;: &quot;host&quot;,
        &quot;instances&quot;: [
          {
            &quot;id&quot;: &quot;host1&quot;,
            &quot;attribute&quot;: {
              &quot;_bk_iam_path_&quot;: [
                &quot;/biz,5/&quot;
              ]
            }
          },
          {
            &quot;id&quot;: &quot;host2&quot;,
            &quot;attribute&quot;: {
              &quot;_bk_iam_path_&quot;: [
                &quot;/biz,5/&quot;
              ]
            }
          }
        ]
      }
    ]
  }
}</code></pre><h1 id="api">直接鉴权 API</h1>
<blockquote>
<p>中大型系统/平台类系统不要使用这个接口</p>
</blockquote>
<p>注意:</p>
<ul>
<li>这个 API 是给非 SDK 接入/无跨系统资源依赖的小型系统/脚本/后台任务使用的.</li>
<li>如果是普通接入系统(非脚本/定时任务等)，建议使用多语言 SDK 进行处理</li>
<li>使用直接鉴权 API，需要提供完整的信息，所有计算会在服务端完成，此时会同其他所有系统共用计算资源，性能可能不及本地 sdk 计算(本地 sdk 还可以做缓存等行为提升性能)</li>
<li>获取某个用户有某个权限的资源列表无法通过此 API 实现; 需要通过策略查询接口查询得到策略，解析表达式后，转换成自身存储的查询条件</li>
<li>该接口耗费服务端资源较大，后续会进行流控/熔断/服务降级</li>
</ul>
<h2 id="1-policy-auth">1. policy auth</h2>
<h3 id="11-url">1.1 URL</h3>
<blockquote>
<p>POST /api/v1/policy/auth</p>
</blockquote>
<h3 id="12-request">1.2 Request</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">系统唯一标识</td>
</tr>
<tr>
<td align="left">subject</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">subject</td>
</tr>
<tr>
<td align="left">action</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">操作</td>
</tr>
<tr>
<td align="left">resources</td>
<td align="left">Array(resource_node)</td>
<td align="left">是</td>
<td align="left">资源实例, 资源类型的顺序必须操作注册时的顺序一致</td>
</tr>
</tbody>
</table>
<p>action</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">操作 ID</td>
</tr>
</tbody>
</table>
<p>subject</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象类型, 当前只支持 user</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象 ID</td>
</tr>
</tbody>
</table>
<p>resource_node</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源系统 ID</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源实例 ID</td>
</tr>
<tr>
<td align="left">attribute</td>
<td align="left">对象</td>
<td align="left">是</td>
<td align="left">资源属性</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
    &quot;system&quot;: &quot;bk_job&quot;,
    &quot;subject&quot;: {
        &quot;type&quot;: &quot;user&quot;,
        &quot;id&quot;: &quot;admin&quot;
    },
    &quot;action&quot;: {
        &quot;id&quot;: &quot;execute&quot;
    },
    &quot;resources&quot;: [{   // 资源类型的顺序必须操作注册时的顺序一致, 否则会导致鉴权失败!
        &quot;system&quot;: &quot;bk_job&quot;,
        &quot;type&quot;: &quot;job&quot;,
        &quot;id&quot;: &quot;ping&quot;,
        &quot;attribute&quot;: {  // 资源的属性值可能有多个, 目前支持string/int/boolean, 以及路径stringList
            &quot;os&quot;: &quot;linux&quot;,
            &quot;_bk_iam_path_&quot;: [&quot;/biz,1/set,2/&quot;],
            &quot;is_ready&quot;: true,
            &quot;area_id&quot;: 200
        }
    }, {
        &quot;system&quot;: &quot;bk_cmdb&quot;,
        &quot;type&quot;: &quot;host&quot;,
        &quot;id&quot;: &quot;192.168.1.1&quot;,
        &quot;attribute&quot;: {} // 外部资源的属性由iam负责查询属性, 接入方不需要传入
    }]
}</code></pre>


<h3 id="13-response">1.3 Response</h3>
<p>Response 字段说明, 表格</p>
<blockquote>
<p>Status: 200 OK</p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: {
        &quot;allowed&quot;: true
    }
}</code></pre>


<h2 id="2-policy-auth-by-resources">2. policy auth by resources</h2>
<p>鉴权场景: 查看一个 <code>用户</code> 有没有 100 台 <code>资源A</code> 的 <code>编辑</code>  权限
限制: resources_list 最大能传 100 个资源</p>
<h3 id="21-url">2.1 URL</h3>
<blockquote>
<p>POST /api/v1/policy/auth_by_resources</p>
</blockquote>
<h3 id="22-request">2.2 Request</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">系统唯一标识</td>
</tr>
<tr>
<td align="left">subject</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">subject</td>
</tr>
<tr>
<td align="left">action</td>
<td align="left">object</td>
<td align="left">是</td>
<td align="left">操作</td>
</tr>
<tr>
<td align="left">resources_list</td>
<td align="left">Array(resources)</td>
<td align="left">是</td>
<td align="left">资源实例列表, 资源类型的顺序必须操作注册时的顺序一致</td>
</tr>
</tbody>
</table>
<p>action</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">操作 ID</td>
</tr>
</tbody>
</table>
<p>subject</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象类型, 当前只支持 user</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象 ID</td>
</tr>
</tbody>
</table>
<p>resources</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">resources</td>
<td align="left">Array(resource_node)</td>
<td align="left">是</td>
<td align="left">一个资源</td>
</tr>
</tbody>
</table>
<p>resource_node</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源系统 ID</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源实例 ID</td>
</tr>
<tr>
<td align="left">attribute</td>
<td align="left">对象</td>
<td align="left">是</td>
<td align="left">资源属性</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
    &quot;system&quot;: &quot;bk_job&quot;,
    &quot;subject&quot;: {
        &quot;type&quot;: &quot;user&quot;,
        &quot;id&quot;: &quot;admin&quot;
    },
    &quot;action&quot;: {
        &quot;id&quot;: &quot;execute&quot;
    },
    &quot;resources_list&quot;: [
        [{   // 第一个资源
            &quot;system&quot;: &quot;bk_job&quot;,
            &quot;type&quot;: &quot;job&quot;,
            &quot;id&quot;: &quot;ping&quot;,
            &quot;attribute&quot;: {
                &quot;os&quot;: &quot;linux&quot;,
                &quot;_bk_iam_path_&quot;: [&quot;/biz,1/set,2/&quot;],
                &quot;is_ready&quot;: true,
                &quot;area_id&quot;: 200
            }
        }, {
            &quot;system&quot;: &quot;bk_cmdb&quot;,
            &quot;type&quot;: &quot;host&quot;,
            &quot;id&quot;: &quot;192.168.1.1&quot;,
            &quot;attribute&quot;: {}
        }],
        [{    // 第二个资源
            &quot;system&quot;: &quot;bk_job&quot;,
            &quot;type&quot;: &quot;job&quot;,
            &quot;id&quot;: &quot;ping2&quot;,
            &quot;attribute&quot;: {
                &quot;os&quot;: &quot;linux&quot;,
                &quot;_bk_iam_path_&quot;: [&quot;/biz,1/set,2/&quot;],
                &quot;is_ready&quot;: true,
                &quot;area_id&quot;: 200
            }
        }, {
            &quot;system&quot;: &quot;bk_cmdb&quot;,
            &quot;type&quot;: &quot;host2&quot;,
            &quot;id&quot;: &quot;192.168.2.2&quot;,
            &quot;attribute&quot;: {}
        }]
    ]
}</code></pre>


<h3 id="23-response">2.3 Response</h3>
<p>Response 字段说明, 表格</p>
<blockquote>
<p>Status: 200 OK</p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: {
        &quot;bk_job,job,ping/bk_cmdb,host,192.168.1.1&quot;: false,
        &quot;bk_job,job,ping2/bk_cmdb,host2,192.168.2.2&quot;: false
    }
}</code></pre>


<h2 id="3-policy-auth-by-actions">3. policy auth by actions</h2>
<p>鉴权场景: 查看一个<code>用户</code>有没有<code>资源A</code>的<code>查看</code>/<code>编辑</code>/<code>删除</code>权限
限制: actions 最大能传 10 个操作</p>
<h3 id="31-url">3.1 URL</h3>
<blockquote>
<p>POST /api/v1/policy/auth_by_actions</p>
</blockquote>
<h3 id="32-request">3.2 Request</h3>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">系统唯一标识</td>
</tr>
<tr>
<td align="left">subject</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">subject</td>
</tr>
<tr>
<td align="left">actions</td>
<td align="left">Array(action)</td>
<td align="left">是</td>
<td align="left">操作</td>
</tr>
<tr>
<td align="left">resources</td>
<td align="left">Array(resource_node)</td>
<td align="left">是</td>
<td align="left">资源实例, 资源类型的顺序必须操作注册时的顺序一致</td>
</tr>
</tbody>
</table>
<p>action</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">操作 ID</td>
</tr>
</tbody>
</table>
<p>subject</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象类型, 当前只支持 user</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象 ID</td>
</tr>
</tbody>
</table>
<p>resource_node</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源系统 ID</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源实例 ID</td>
</tr>
<tr>
<td align="left">attribute</td>
<td align="left">对象</td>
<td align="left">是</td>
<td align="left">资源属性</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
    &quot;system&quot;: &quot;bk_job&quot;,
    &quot;subject&quot;: {
        &quot;type&quot;: &quot;user&quot;,
        &quot;id&quot;: &quot;admin&quot;
    },
    &quot;actions&quot;: [{
        &quot;id&quot;: &quot;execute&quot;
    }, {
        &quot;id&quot;: &quot;view&quot;
    }],
    &quot;resources&quot;: [{   // 资源类型的顺序必须操作注册时的顺序一致, 否则会导致鉴权失败!
        &quot;system&quot;: &quot;bk_job&quot;,
        &quot;type&quot;: &quot;job&quot;,
        &quot;id&quot;: &quot;ping&quot;,
        &quot;attribute&quot;: {  // 资源的属性值可能有多个, 目前支持string/int/boolean, 以及路径stringList
            &quot;os&quot;: &quot;linux&quot;,
            &quot;_bk_iam_path_&quot;: [&quot;/biz,1/set,2/&quot;],
            &quot;is_ready&quot;: true,
            &quot;area_id&quot;: 200
        }
    }, {
        &quot;system&quot;: &quot;bk_cmdb&quot;,
        &quot;type&quot;: &quot;host&quot;,
        &quot;id&quot;: &quot;192.168.1.1&quot;,
        &quot;attribute&quot;: {}  // 外部资源的属性由iam负责查询属性, 接入方不需要传入
    }]
}</code></pre>


<h3 id="33-response">3.3 Response</h3>
<blockquote>
<p>Status: 200 OK</p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: {
        &quot;execute&quot;: true,
        &quot;view&quot;: false
    }
}</code></pre><h1 id="url">生成无权限申请 URL</h1>
<blockquote>
<p>此文档向接入系统说明接入系统在用户无权限需要提醒用户申请时使用的 api</p>
</blockquote>
<h3 id="_1">接入系统权限申请</h3>
<p>用户在接入系统进行操作时, 如果没有某些权限, 此时需要跳转到权限中心申请对应权限.
权限中心申请页面, 需要自动填充相关的申请信息.
所以, 需要接入系统, 将相关信息预先提交到权限中心, 权限中心返回<code>权限申请URL</code></p>
<p>流程:
1. 组装权限申请信息
2. 请求 API, 获取权限申请 url
3. url 渲染到前端表单, 用户点击后, 跳转到权限中心的权限申请页面</p>
<p>具体无权限交互可以查看 <a href="../../../HowTo/Solutions/NoPermissionApply.md">文档</a></p>
<h4 id="url_1">URL</h4>
<blockquote>
<p>POST /api/c/compapi/v2/iam/application/
<code>特别说明:该 API 为ESB API</code> <a href="../01-Overview/01-BackendAPIvsESBAPI.md">ESB API 说明</a></p>
</blockquote>
<h4 id="_2">通用参数</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">bk_app_code</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">应用 ID</td>
</tr>
<tr>
<td align="left">bk_app_secret</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">安全密钥(应用 TOKEN)，可以通过 蓝鲸智云开发者中心 -&gt; 点击应用 ID -&gt; 基本信息 获取</td>
</tr>
<tr>
<td align="left">bk_token</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">当前用户登录态，bk_token 与 bk_username 必须一个有效，bk_token 可以通过 Cookie 获取</td>
</tr>
<tr>
<td align="left">bk_username</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">当前用户用户名，仅仅在 ESB 里配置免登录态验证白名单中的应用，才可以用此字段指定当前用户</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">系统 id</td>
</tr>
<tr>
<td align="left">actions</td>
<td align="left">数组</td>
<td align="left">是</td>
<td align="left">申请权限的操作</td>
</tr>
</tbody>
</table>
<p>actions</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">操作 id</td>
</tr>
<tr>
<td align="left">related_resource_types</td>
<td align="left">数组</td>
<td align="left">是</td>
<td align="left">操作关联的资源类型, <code>资源类型的顺序必须操作注册时的顺序一致</code> (<a href="../../../Reference/API/02-Model/13-Action.md">操作注册 API</a>)</td>
</tr>
</tbody>
</table>
<p>related_resource_types</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型的系统 id</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型</td>
</tr>
<tr>
<td align="left">instances</td>
<td align="left">数组[数组]</td>
<td align="left">否</td>
<td align="left">资源实例,可选</td>
</tr>
<tr>
<td align="left">attributes</td>
<td align="left">数组</td>
<td align="left">否</td>
<td align="left">实例属性,可选</td>
</tr>
</tbody>
</table>
<p>related_resource_types.instances</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源实例 id</td>
</tr>
</tbody>
</table>
<p>related_resource_types.attributes</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">属性 key</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">属性 key 名称</td>
</tr>
<tr>
<td align="left">values</td>
<td align="left">数组</td>
<td align="left">是</td>
<td align="left">属性的可选值</td>
</tr>
</tbody>
</table>
<p>related_resource_types.attributes.values</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">属性 value</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">属性 value 名称</td>
</tr>
</tbody>
</table>
<ol>
<li>无关联资源类型的操作示例:</li>
</ol>
<p>系统<code>bk_job</code>的<code>create_job</code>操作未关联资源类型</p>
<pre class="codehilite"><code class="language-json">{
  &quot;system&quot;: &quot;bk_job&quot;,  # 权限的系统
  &quot;actions&quot;: [
    {
      &quot;id&quot;: &quot;create_job&quot;,  # 操作id
      &quot;related_resource_types&quot;: []  # related_resource_types 空数组表示操作不关联资源类型
    }
  ]
}</code></pre>


<ol>
<li>资源拓扑路径的操作示例:</li>
</ol>
<p>系统<code>bk_job</code>的<code>view_job</code>操作关联资源类型<code>job</code>, 并且注册了实例视图 <code>业务(biz)</code>-<code>作业(job)</code>, 这个实例视图拓扑路径有 2 层</p>
<pre class="codehilite"><code class="language-json">{
  &quot;system&quot;: &quot;bk_job&quot;,  # 权限的系统
  &quot;actions&quot;: [
    {
      &quot;id&quot;: &quot;view_job&quot;,  # 操作id
      &quot;related_resource_types&quot;: [
        {
          &quot;system&quot;: &quot;bk_job&quot;,  # 资源类型所属的系统id
          &quot;type&quot;: &quot;job&quot;,  # 资源类型
          &quot;instances&quot;: [
            [  # 一个数组表示一个实例的拓扑路径, 拓扑路径必须与实例视图的资源链路一致, 业务(biz)-作业(job)
              {
                &quot;type&quot;: &quot;biz&quot;,  # 实例视图中资源的第一层业务
                &quot;id&quot;: &quot;biz1&quot;,
              },
              {
                &quot;type&quot;: &quot;job&quot;,  # 实例视图中资源拓扑路径的第二层作业
                &quot;id&quot;: &quot;job1&quot;,
              }
            ]
          ]
        }
      ]
    }
  ]
}</code></pre>


<ol>
<li>关联多个资源类型的操作示例:</li>
</ol>
<p>系统<code>bk_job</code>的<code>execute_job</code>操作关联资源类型<code>job</code>与系统<code>bk_cmdb</code>的资源类型<code>host</code>,
<code>job</code>注册了实例视图 <code>业务(biz)</code>-<code>作业(job)</code>, 这个实例视图拓扑路径有 2 层,
<code>bk_cmdb</code>的资源类型<code>host</code>注册实例视图, <code>业务(biz)</code>-<code>集群(set)</code>-<code>模块(module)</code>-<code>主机(host)</code>, 这个实例视图拓扑路径有 4 层</p>
<pre class="codehilite"><code class="language-json">{
  &quot;system&quot;: &quot;bk_job&quot;,  # 权限的系统
  &quot;actions&quot;: [
    {
      &quot;id&quot;: &quot;execute_job&quot;,  # 操作id
      &quot;related_resource_types&quot;: [  # 关联几个资源类型, 这里就必须传几个item, 并且资源类型的顺序必须与注册操作时资源类型的顺序一致
        {
          &quot;system&quot;: &quot;bk_job&quot;,
          &quot;type&quot;: &quot;job&quot;,
          &quot;instances&quot;: [
            [  # 业务(biz)-作业(job)
              {
                &quot;type&quot;: &quot;biz&quot;,
                &quot;id&quot;: &quot;biz1&quot;,
              },
              {
                &quot;type&quot;: &quot;job&quot;,
                &quot;id&quot;: &quot;job1&quot;,
              }
            ]
          ]
        },
        {
          &quot;system&quot;: &quot;bk_cmdb&quot;,  # 资源类型所属的系统id
          &quot;type&quot;: &quot;host&quot;,  # 操作依赖的另外一个资源类型
          &quot;instances&quot;: [
            [  # 4层的拓扑路径, 必须与实例视图的资源链路一致: 业务(biz)-集群(set)-模块(module)-主机(host)
              {
                &quot;type&quot;: &quot;biz&quot;,
                &quot;id&quot;: &quot;biz1&quot;,
              }, {
                &quot;type&quot;: &quot;set&quot;,
                &quot;id&quot;: &quot;set1&quot;,
              }, {
                &quot;type&quot;: &quot;module&quot;,
                &quot;id&quot;: &quot;module1&quot;,
              }, {
                &quot;type&quot;: &quot;host&quot;,
                &quot;id&quot;: &quot;host1&quot;,
              }
            ]
          ],
          &quot;attributes&quot;: [  # 支持配置实例的属性值, attributes与instances的组合关系为AND
            {
              &quot;id&quot;: &quot;os&quot;,  # 属性的key
              &quot;name&quot;: &quot;操作系统&quot;,
              &quot;values&quot;: [
                {
                  &quot;id&quot;: &quot;linux&quot;,  # 属性的value, 可以有多个
                  &quot;name&quot;: &quot;linux&quot;
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}</code></pre>


<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
  &quot;data&quot;: {
    &quot;url&quot;: &quot;https://{PAAS_DOMAIN}/o/bk_iam_app/perm-apply?system_id=bk_job&amp;amp;tid=09d432dccac74ec4aa17629f5f83715f&quot;  # 链接有效期10分钟
  },
  &quot;result&quot;: true,
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;OK&quot;
}</code></pre>


<p>data</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">url</td>
<td align="left">字符串</td>
<td align="left">权限申请重定向 URL</td>
</tr>
</tbody>
</table>
<h3 id="_3">返回结果错误说明</h3>
<p>由于跳转申请后，产品上需要显示的时资源实例名称，而不是 ID，所以权限中心会回调查询接入系统
1. 如果未提供查询相关接口,则错误码 code=1902204
2. 如果查询不到资源实例的名称或接入系统不存在对应的资源实例，则错误码 code=1902416
3. 会校验 <code>related_resource_types</code>操作关联的资源类型, <code>资源类型的顺序必须操作注册时的顺序一致</code> (<a href="../../../Reference/API/02-Model/13-Action.md">操作注册 API</a>), 如果不一致, 错误码 <code>1902417</code>, 具体见文档 <a href="../../../HowTo/FAQ/ErrorCode.md">错误码</a></p><h2 id="_1">第三方鉴权失败返回权限申请数据协议</h2>
<h4 id="_2">背景</h4>
<p>标准运维调用作业平台执行作业, 如果是因为鉴权失败导致执行失败, 作业平台需要返回以下错误信息到标准运维, 标准运维使用以下数据展示需要申请的权限信息, 然后再调用以上 API 到权限中心申请权限</p>
<h4 id="http">建议：接口 HTTP 状态码</h4>
<p>http status_code = <code>200</code></p>
<h3 id="response-body">返回接口 response body 协议</h3>
<blockquote>
<p><code>字段code = 9900403 , 且需要有 permission字段返回需要对应申请的权限数据</code></p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
  &quot;code&quot;: 9900403,
  &quot;message&quot;: &quot;&quot;,
  &quot;data&quot;: null,
  &quot;permission&quot;: {
    &quot;system&quot;: &quot;bk_job&quot;,
    &quot;system_name&quot;: &quot;作业平台&quot;,
    &quot;actions&quot;: [
      {
        &quot;id&quot;: &quot;execute_job&quot;,
        &quot;name&quot;: &quot;执行作业&quot;,
        &quot;related_resource_types&quot;: [
          {
            &quot;system&quot;: &quot;bk_job&quot;,
            &quot;system_name&quot;: &quot;作业平台&quot;,
            &quot;type&quot;: &quot;job&quot;,
            &quot;type_name&quot;: &quot;作业&quot;,
            &quot;instances&quot;: [
              [
                {
                  &quot;type&quot;: &quot;job&quot;,
                  &quot;type_name&quot;: &quot;作业&quot;,
                  &quot;id&quot;: &quot;job1&quot;,
                  &quot;name&quot;: &quot;作业1&quot;
                }
              ]
            ]
          },
          {
            &quot;system&quot;: &quot;bk_cmdb&quot;,
            &quot;system_name&quot;: &quot;配置平台&quot;,
            &quot;type&quot;: &quot;host&quot;,
            &quot;type_name&quot;: &quot;主机&quot;,
            &quot;instances&quot;: [
              [
                {
                  &quot;type&quot;: &quot;biz&quot;,
                  &quot;type_name&quot;: &quot;业务&quot;,
                  &quot;id&quot;: &quot;biz1&quot;,
                  &quot;name&quot;: &quot;业务1&quot;
                },
                {
                  &quot;type&quot;: &quot;set&quot;,
                  &quot;type_name&quot;: &quot;集群&quot;,
                  &quot;id&quot;: &quot;set1&quot;,
                  &quot;name&quot;: &quot;集群1&quot;
                },
                {
                  &quot;type&quot;: &quot;module&quot;,
                  &quot;type_name&quot;: &quot;模块&quot;,
                  &quot;id&quot;: &quot;module1&quot;,
                  &quot;name&quot;: &quot;模块1&quot;
                },
                {
                  &quot;type&quot;: &quot;host&quot;,
                  &quot;type_name&quot;: &quot;主机&quot;,
                  &quot;id&quot;: &quot;host1&quot;,
                  &quot;name&quot;: &quot;主机1&quot;
                }
              ]
            ]
          }
        ]
      }
    ]
  }
}</code></pre><h1 id="_1">资源拓扑授权/回收</h1>
<h3 id="_2">参数说明</h3>
<p><code>resources.path</code>的说明</p>
<p>示例 1: 拓扑层级授权到资源实例, <em>业务 1-集群 2-主机 1</em></p>
<pre class="codehilite"><code class="language-json">{
  &quot;system&quot;: &quot;bk_cmdb&quot;,
  &quot;type&quot;: &quot;host&quot;,
  &quot;path&quot;: [
    {
      &quot;type&quot;: &quot;biz&quot;,
      &quot;id&quot;: &quot;1&quot;,
      &quot;name&quot;: &quot;biz1&quot;
    },
    {
      &quot;type&quot;: &quot;set&quot;,
      &quot;id&quot;: &quot;2&quot;,
      &quot;name&quot;: &quot;set2&quot;
    },
    {
      &quot;type&quot;: &quot;host&quot;,
      &quot;id&quot;: &quot;1&quot;,
      &quot;name&quot;: &quot;host1&quot;
    }
  ]
}</code></pre>


<p>示例 2: 拓扑层级前缀, <em>业务 1-任意集群</em>, 此时只有业务 1 的集群下的主机会有权限</p>
<p><code>注意</code>: </p>
<ul>
<li>业务 1 下的主机与业务 1 下任意集群的主机的定义是不一样的</li>
<li><code>业务1下的主机</code>包含业务 1 下可能的<code>所有拓扑</code>下的所有主机</li>
<li><code>业务1下集群的所有主机</code>, 只包含特定拓扑 <code>业务-集群</code> 下的所有主机</li>
<li>为避免权限放大, 在拓扑层级授权时需要把选择到的拓扑节点的下一级的任意带上, 比如选择的是 <code>业务1</code>, 授权时传 <code>业务1-任意集群</code></li>
</ul>
<pre class="codehilite"><code class="language-json">{
  &quot;system&quot;: &quot;bk_cmdb&quot;,
  &quot;type&quot;: &quot;host&quot;,
  &quot;path&quot;: [
    {
      &quot;type&quot;: &quot;biz&quot;,
      &quot;id&quot;: &quot;1&quot;,
      &quot;name&quot;: &quot;biz1&quot;
    },
    {
      &quot;type&quot;: &quot;set&quot;,
      &quot;id&quot;: &quot;*&quot;,
      &quot;name&quot;: &quot;&quot;
    }
  ]
}</code></pre>


<h3 id="_3">资源拓扑授权/回收</h3>
<p>对单个资源拓扑, 单个操作的授权与回收接口</p>
<p><code>注意</code>: </p>
<ul>
<li><code>resources.type</code>的是操作关联的资源类型, <code>resources.path</code>是资源类型能选择的拓扑层级</li>
<li><code>resources.path</code>的路径必须与接入系统注册的资源实例选择视图的拓扑层级一致, 否则授权的拓扑层级在权限中心会出现在视图中选择不中(打不上勾)的情况</li>
</ul>
<hr />
<h4 id="url">URL</h4>
<blockquote>
<p>POST /api/c/compapi/v2/iam/authorization/path/
<code>特别说明:该 API 为ESB API</code> <a href="../01-Overview/01-BackendAPIvsESBAPI.md">ESB API 说明</a></p>
</blockquote>
<h4 id="_4">通用参数</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">bk_app_code</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">应用 ID</td>
</tr>
<tr>
<td align="left">bk_app_secret</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">安全密钥(应用 TOKEN)，可以通过 蓝鲸智云开发者中心 -&gt; 点击应用 ID -&gt; 基本信息 获取</td>
</tr>
<tr>
<td align="left">bk_token</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">当前用户登录态，bk_token 与 bk_username 必须一个有效，bk_token 可以通过 Cookie 获取</td>
</tr>
<tr>
<td align="left">bk_username</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">当前用户用户名，仅仅在 ESB 里配置免登录态验证白名单中的应用，才可以用此字段指定当前用户</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">asynchronous</td>
<td align="left">布尔</td>
<td align="left">是</td>
<td align="left">是否异步调用, 默认 否, 当前只支持同步</td>
</tr>
<tr>
<td align="left">operate</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">grant 或 revoke</td>
</tr>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">系统 id</td>
</tr>
<tr>
<td align="left">action</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">操作</td>
</tr>
<tr>
<td align="left">subject</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象</td>
</tr>
<tr>
<td align="left">resources</td>
<td align="left">数组[对象]</td>
<td align="left">是</td>
<td align="left">资源拓扑, 资源类型的顺序必须操作注册时的顺序一致</td>
</tr>
</tbody>
</table>
<p>action</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">操作 ID</td>
</tr>
</tbody>
</table>
<p>subject</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象类型, 当前只支持 user</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象 ID</td>
</tr>
</tbody>
</table>
<p>resources</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源系统 ID</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型 ID</td>
</tr>
<tr>
<td align="left">path</td>
<td align="left">数组[对象]</td>
<td align="left">是</td>
<td align="left">资源的拓扑</td>
</tr>
</tbody>
</table>
<p>resources.path</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">拓扑节点类型 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">拓扑节点实例 ID</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">拓扑节点实例名称</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
  &quot;asynchronous&quot;: false,  # 默认false, 当前只支持同步
  &quot;operate&quot;: &quot;grant&quot;,   # grant 授权 revoke 回收
  &quot;system&quot;: &quot;bk_cmdb&quot;,
  &quot;action&quot;: {
    &quot;id&quot;: &quot;edit_host&quot;
  },
  &quot;subject&quot;: {  # 当前只能对user授权
    &quot;type&quot;: &quot;user&quot;,
    &quot;id&quot;: &quot;admin&quot;
  },
  &quot;resources&quot;: [  # 操作依赖多个资源类型的情况下, 表示一个组合资源, 资源类型的顺序必须操作注册时的顺序一致
    {
      &quot;system&quot;: &quot;bk_cmdb&quot;,
      &quot;type&quot;: &quot;host&quot;,
      &quot;path&quot;: [
        {
          &quot;type&quot;: &quot;biz&quot;,
          &quot;id&quot;: &quot;1&quot;,
          &quot;name&quot;: &quot;biz1&quot;
        },{
          &quot;type&quot;: &quot;set&quot;,
          &quot;id&quot;: &quot;*&quot;,
          &quot;name&quot;: &quot;&quot;
        }
      ]
    }
  ]
}</code></pre>


<h4 id="response">Response</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">policy_id</td>
<td align="left">数值</td>
<td align="left">权限策略 id</td>
<td align="left"></td>
</tr>
</tbody>
</table>
<blockquote>
<p>Status: 200 OK</p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;ok&quot;,
  &quot;data&quot;: {
    &quot;policy_id&quot;: 1
  }
}</code></pre>


<h4 id="response-when-async">Response when async (未实现)</h4>
<pre class="codehilite"><code class="language-json">{
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;ok&quot;,
  &quot;data&quot;: {
    &quot;task_id&quot;: 1  // 任务id
  }
}</code></pre><h1 id="_1">批量资源拓扑授权/回收</h1>
<p>对多个资源拓扑, 多个操作的授权与回收接口</p>
<p><code>resources.paths</code>是批量的资源实例拓扑, 具体说明可以参考<a href="../06-GrantRevoke/01-Topology.md">资源拓扑授权/回收</a></p>
<hr />
<h4 id="url">URL</h4>
<blockquote>
<p>POST /api/c/compapi/v2/iam/authorization/batch_path/
<code>特别说明:该 API 为ESB API</code> <a href="../01-Overview/01-BackendAPIvsESBAPI.md">ESB API 说明</a></p>
</blockquote>
<h4 id="_2">通用参数</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">bk_app_code</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">应用 ID</td>
</tr>
<tr>
<td align="left">bk_app_secret</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">安全密钥(应用 TOKEN)，可以通过 蓝鲸智云开发者中心 -&gt; 点击应用 ID -&gt; 基本信息 获取</td>
</tr>
<tr>
<td align="left">bk_token</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">当前用户登录态，bk_token 与 bk_username 必须一个有效，bk_token 可以通过 Cookie 获取</td>
</tr>
<tr>
<td align="left">bk_username</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">当前用户用户名，仅仅在 ESB 里配置免登录态验证白名单中的应用，才可以用此字段指定当前用户</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">asynchronous</td>
<td align="left">布尔</td>
<td align="left">是</td>
<td align="left">是否异步调用, 默认 否, 当前只支持同步</td>
</tr>
<tr>
<td align="left">operate</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">grant 或 revoke</td>
</tr>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">系统 id</td>
</tr>
<tr>
<td align="left">actions</td>
<td align="left">数组[对象]</td>
<td align="left">是</td>
<td align="left">操作</td>
</tr>
<tr>
<td align="left">subject</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象</td>
</tr>
<tr>
<td align="left">resources</td>
<td align="left">数组[对象]</td>
<td align="left">是</td>
<td align="left">资源拓扑, 资源类型的顺序必须操作注册时的顺序一致</td>
</tr>
</tbody>
</table>
<p>actions</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">操作 ID</td>
</tr>
</tbody>
</table>
<p>subject</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象类型, 当前只支持 user</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">授权对象 ID</td>
</tr>
</tbody>
</table>
<p>resources</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源系统 ID</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">资源类型 ID</td>
</tr>
<tr>
<td align="left">paths</td>
<td align="left">数组[[对象]]</td>
<td align="left">是</td>
<td align="left">批量资源拓扑，<code>最多1000个</code></td>
</tr>
</tbody>
</table>
<p>resources.paths</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">type</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">拓扑节点类型 ID</td>
</tr>
<tr>
<td align="left">id</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">拓扑节点实例 ID</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">字符串</td>
<td align="left">是</td>
<td align="left">拓扑节点实例名称</td>
</tr>
</tbody>
</table>
<pre class="codehilite"><code class="language-json">{
  &quot;asynchronous&quot;: false,
  &quot;operate&quot;: &quot;grant&quot;,
  &quot;system&quot;: &quot;bk_cmdb&quot;,
  &quot;actions&quot;: [  # 批量的操作
    {
      &quot;id&quot;: &quot;edit_host&quot;
    }
  ],
  &quot;subject&quot;: {
    &quot;type&quot;: &quot;user&quot;,
    &quot;id&quot;: &quot;admin&quot;
  },
  &quot;resources&quot;: [
    {  # 操作关联的资源类型, 必须与所有的actions都匹配, 资源类型的顺序必须操作注册时的顺序一致
      &quot;system&quot;: &quot;bk_cmdb&quot;,
      &quot;type&quot;: &quot;host&quot;,
      &quot;paths&quot;: [  # 批量资源拓扑
        [
          {
            &quot;type&quot;: &quot;biz&quot;,
            &quot;id&quot;: &quot;1&quot;,
            &quot;name&quot;: &quot;biz1&quot;
          },
          {
            &quot;type&quot;: &quot;set&quot;,
            &quot;id&quot;: &quot;*&quot;,
            &quot;name&quot;: &quot;&quot;
          }
        ]
      ]
    }
  ]
}</code></pre>


<h4 id="response">Response</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">policy_id</td>
<td align="left">数值</td>
<td align="left">权限策略 id</td>
</tr>
<tr>
<td align="left">action</td>
<td align="left">对象</td>
<td align="left">操作</td>
</tr>
</tbody>
</table>
<blockquote>
<p>Status: 200 OK</p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;ok&quot;,
  &quot;data&quot;: [
    {
      &quot;action&quot;: {
        &quot;id&quot;: &quot;edit_host&quot;
      },
      &quot;policy_id&quot;: 1
    }
  ]
}</code></pre>


<h4 id="response-when-async">Response when async (未实现)</h4>
<pre class="codehilite"><code class="language-json">{
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;ok&quot;,
  &quot;data&quot;: {
    &quot;task_id&quot;: 1  // 任务id
  }
}</code></pre><h1 id="_1">新建关联属性授权接口</h1>
<h3 id="_2">接口基本说明</h3>
<ul>
<li>
<p>背景：</p>
<ul>
<li>接入系统上批量资源实例被创建时，对应的创建者应该需要赋予依赖这批实例的某个属性的相关权限<ul>
<li>比如批量作业创建时，创建者需要有属性为 creator=xxx 的作业的编辑、删除和查看权限</li>
</ul>
</li>
</ul>
</li>
<li>
<p>流程:</p>
<ul>
<li>
<ol>
<li><strong>用户</strong>在<strong>接入系统</strong>上产生资源实例</li>
</ol>
</li>
<li>
<ol>
<li><strong>接入系统</strong>请求 API,  <strong>权限中心</strong>根据 <a href="../02-Model/19-ResourceCreatorAction.md">新建关联</a> 配置对应创建者进行授权</li>
</ol>
</li>
</ul>
</li>
<li>
<p>接口描述： </p>
<ul>
<li>接入系统根据资源实例创建，对创建者进行相关属性授权</li>
</ul>
</li>
<li>
<p><code>接口特别说明</code></p>
<ul>
<li>新建关联的 Actions 对应的依赖资源类型必须 selection_mode 为 all 或 attribute（Action 无关联实例除外）且只能有一种依赖资源，否则新建关联授权时会被<code>自动忽略</code></li>
</ul>
</li>
</ul>
<hr />
<h4 id="url">URL</h4>
<blockquote>
<p>POST /api/c/compapi/v2/iam/authorization/resource_creator_action_attribute/
<code>特别说明:该 API 为ESB API</code> <a href="../01-Overview/01-BackendAPIvsESBAPI.md">ESB API 说明</a></p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<ul>
<li>通用参数</li>
</ul>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">bk_app_code</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">应用 ID</td>
</tr>
<tr>
<td align="left">bk_app_secret</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">安全密钥(应用 TOKEN)，可以通过 蓝鲸智云开发者中心 -&gt; 点击应用 ID -&gt; 基本信息 获取</td>
</tr>
<tr>
<td align="left">bk_token</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">当前用户登录态，bk_token 与 bk_username 必须一个有效，bk_token 可以通过 Cookie 获取</td>
</tr>
<tr>
<td align="left">bk_username</td>
<td align="left">string</td>
<td align="left">否</td>
<td align="left">当前用户用户名，仅仅在 ESB 里配置免登录态验证白名单中的应用，才可以用此字段指定当前用户</td>
</tr>
</tbody>
</table>
<ul>
<li>接口参数</li>
</ul>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">系统唯一标识</td>
</tr>
<tr>
<td align="left">type</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源类型的唯一标识</td>
</tr>
<tr>
<td align="left">creator</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源实例的创建者</td>
</tr>
<tr>
<td align="left">attributes</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">资源属性列表，<code>多个属性之间的权限逻辑是AND</code></td>
</tr>
</tbody>
</table>
<p>attributes 列表的元素说明</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源属性的唯一标识</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源属性的名称</td>
</tr>
<tr>
<td align="left">values</td>
<td align="left">array(object)</td>
<td align="left">是</td>
<td align="left">资源属性的值，支持多个值，<code>多个值之间的权限逻辑是OR</code></td>
</tr>
</tbody>
</table>
<p>values 列表的元素说明</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源属性值的唯一标识</td>
</tr>
<tr>
<td align="left">name</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">资源属性值的名称</td>
</tr>
</tbody>
</table>
<h4 id="request">Request</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;system&quot;: &quot;bk_sops&quot;,
    &quot;type&quot;:&quot;task&quot;,
    &quot;creator&quot;:&quot;admin&quot;,
    &quot;attributes&quot;: [
        {
            &quot;id&quot;:&quot;owner&quot;,
            &quot;name&quot;:&quot;任务所属者&quot;,
            &quot;values&quot;: [
                {
                    &quot;id&quot;: &quot;admin&quot;,
                    &quot;name&quot;: &quot;admin(管理员)&quot;
                }
            ]
        }
    ]
}</code></pre>


<h4 id="response">Response</h4>
<p>data 数组元素</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">action</td>
<td align="left">object</td>
<td align="left">creator 被授权对应的 Action</td>
</tr>
<tr>
<td align="left">policy_id</td>
<td align="left">int</td>
<td align="left">creator 被授权对应的策略 ID</td>
</tr>
</tbody>
</table>
<p>action</p>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">id</td>
<td align="left">string</td>
<td align="left">操作 ID</td>
</tr>
</tbody>
</table>
<blockquote>
<p>Status: 200 OK</p>
</blockquote>
<pre class="codehilite"><code class="language-json">{
  &quot;data&quot;: [  // 表示creator被授权对应的Action和策略ID列表
    {
        &quot;action&quot;: {
            &quot;id&quot;: &quot;edit&quot;
        },
        &quot;policy_id&quot;: 1
    },
    {
        &quot;action&quot;: {
            &quot;id&quot;: &quot;list&quot;
        },
        &quot;policy_id&quot;: 2
    },
    {
        &quot;action&quot;: {
            &quot;id&quot;: &quot;delete&quot;
        },
        &quot;policy_id&quot;: 3
    },
    {
        &quot;action&quot;: {
            &quot;id&quot;: &quot;view&quot;
        },
        &quot;policy_id&quot;: 4
    }
  ],
  &quot;result&quot;: true,
  &quot;code&quot;: 0,
  &quot;message&quot;: &quot;OK&quot;
}</code></pre><h1 id="api">查询类 API</h1>
<h2 id="_1">背景</h2>
<p>接入系统通过 LBAC 方案接入, 可以自由控制资源权限的授权和回收;</p>
<p>此时能感知到对应策略的<code>PolicyID</code>;</p>
<p>权限中心后台提供了以下查询接口, 用于接入系统查询<code>自己系统</code>的<code>权限信息</code></p>
<p>可以配合策略变更的<code>发布-订阅</code>机制, 做定时全量的策略拉取, 用于数据校准;</p>
<p>(类似于 k8s 的 list-watch 机制, list 调用全量查询接口, watch 使用发布订阅机制感知到增量变化)</p>
<h2 id="_2">接口前置说明</h2>
<p>请阅读 <a href="../01-Overview/02-APIBasicInfo.md">接口协议前置说明</a></p><h1 id="policy-get">policy get 获取某条策略详情</h1>
<p>根据策略 ID, 获取策略详情</p>
<p>注意:
- 如果<code>policy_id</code>对应记录不存在(错误的 ID 或者已经被删除), 将会返回<code>code=1901404(NotFoundError)</code> 
- 只能查询自己系统的策略详情, 如果是其他系统的 policy ID, 将会返回<code>code=1901403(ForbiddenError)</code> 
- 返回结果中<code>expired_at</code>为过期时间, 需二次判定是否过期(查回来一刻可能还没过期, 但是传递使用时可能已过期)</p>
<h4 id="url">URL</h4>
<blockquote>
<p>GET /api/v1/systems/{system_id}/policies/{policy_id}</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">policy_id</td>
<td align="left">integer</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">策略 ID</td>
</tr>
</tbody>
</table>
<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: {
        &quot;version&quot;: &quot;1&quot;,
        &quot;id&quot;: 2,
        &quot;system&quot;: &quot;bk_cmdb&quot;,
        &quot;subject&quot;: {
            &quot;type&quot;: &quot;user&quot;,
            &quot;id&quot;: &quot;admin&quot;,
            &quot;name&quot;: &quot;管理员&quot;
        },
        &quot;action&quot;: {
            &quot;id&quot;: &quot;view_host&quot;
        },
        &quot;expression&quot;: {
            &quot;content&quot;: [
                {
                    &quot;field&quot;: &quot;host.id&quot;,
                    &quot;op&quot;: &quot;any&quot;,
                    &quot;value&quot;: []
                }
            ],
            &quot;op&quot;: &quot;OR&quot;
        },
        &quot;expired_at&quot;: 4102444800
    }
}</code></pre><h1 id="policy-list">policy list 拉取系统下某个操作的策略列表</h1>
<p>用于接入系统批量拉取某个 action 的所有策略; 全量带翻页; 
接入系统可以利用这个接口, 定期拉取策略进行全量校验及<code>补偿</code></p>
<p>关于 timestamp 的说明:
- 由于策略是带过期时间的, 翻页查询的过程是一个时间跨度比较长的操作, 如果每一页实时查询<code>当前未过期</code>的策略列表, 那么整体结果集及固定页码里面的策略内容将会动态变化; 接入系统无法真正拉取某个操作<code>全量</code>策略
- 这个接口拉取第一页, 默认设置<code>timestamp</code>为当天<code>00:00:00</code>的时间戳, 例如<code>1593273600</code>
- 当翻第二页到最后一页的过程中, 接入系统建议将<code>timestamp</code>作为参数传入; 以定位一个<code>锚点</code>; 防止翻页过程中跨天导致的策略列表动态变化; (如果不担心这个, 可以一直不传)
- <code>timestamp</code> 最小为<code>当前时间-24小时</code></p>
<p>注意:
- 查询回去的每条策略中<code>expired_at</code>为过期时间, 接入系统在使用前需要再次判定是否过期
- 只能查询自己系统的<code>action_id</code>, 如果是在本系统找不到这个<code>action_id</code>不存在, 将会返回<code>code=1901404(NotFoundError)</code> </p>
<hr />
<h4 id="url">URL</h4>
<blockquote>
<p>GET  /api/v1/systems/{system_id}/policies</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">action_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">query</td>
<td align="left">操作 ID(action id), 必须是这个系统注册到权限中心的合法 Action</td>
</tr>
<tr>
<td align="left">page</td>
<td align="left">integer</td>
<td align="left">否</td>
<td align="left">query</td>
<td align="left">页码, 不传默认为<code>1</code></td>
</tr>
<tr>
<td align="left">page_size</td>
<td align="left">integer</td>
<td align="left">否</td>
<td align="left">query</td>
<td align="left">单页大小,不传默认<code>100</code>, 限制单页最大<code>500</code></td>
</tr>
<tr>
<td align="left">timestamp</td>
<td align="left">integer</td>
<td align="left">否</td>
<td align="left">query</td>
<td align="left">查询时间戳, 锚点</td>
</tr>
</tbody>
</table>
<p>示例: <code>action_id=edit_host&amp;page=1&amp;page_size=100&amp;timestamp=1592899208</code></p>
<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: {
        &quot;metadata&quot;: {
            &quot;system&quot;: &quot;bk_cmdb&quot;,
            &quot;action&quot;: {
                &quot;id&quot;: &quot;edit_host&quot;
            },
            &quot;timestamp&quot;: 1593273600
        },
        &quot;count&quot;: 3,
        &quot;results&quot;: [
            {
                &quot;version&quot;: &quot;1&quot;,
                &quot;id&quot;: 3,
                &quot;subject&quot;: {
                    &quot;type&quot;: &quot;user&quot;,
                    &quot;id&quot;: &quot;test2&quot;,
                    &quot;name&quot;: &quot;test2&quot;
                },
                &quot;expression&quot;: {
                    &quot;content&quot;: [
                        {
                            &quot;field&quot;: &quot;host.id&quot;,
                            &quot;op&quot;: &quot;eq&quot;,
                            &quot;value&quot;: &quot;192.168.1.1&quot;
                        }
                    ],
                    &quot;op&quot;: &quot;OR&quot;
                },
                &quot;expired_at&quot;: 4102444800
            },
            {
                &quot;version&quot;: &quot;1&quot;,
                &quot;id&quot;: 4,
                &quot;subject&quot;: {
                    &quot;type&quot;: &quot;user&quot;,
                    &quot;id&quot;: &quot;test1&quot;,
                    &quot;name&quot;: &quot;test1&quot;
                },
                &quot;expression&quot;: {
                    &quot;content&quot;: [
                        {
                            &quot;field&quot;: &quot;host.system&quot;,
                            &quot;op&quot;: &quot;eq&quot;,
                            &quot;value&quot;: &quot;linux&quot;
                        }
                    ],
                    &quot;op&quot;: &quot;OR&quot;
                },
                &quot;expired_at&quot;: 4102444800
            },
            {
                &quot;version&quot;: &quot;1&quot;,
                &quot;id&quot;: 7,
                &quot;subject&quot;: {
                    &quot;type&quot;: &quot;user&quot;,
                    &quot;id&quot;: &quot;admin&quot;,
                    &quot;name&quot;: &quot;管理员&quot;
                },
                &quot;expression&quot;: {
                    &quot;content&quot;: [
                        {
                            &quot;field&quot;: &quot;host.id&quot;,
                            &quot;op&quot;: &quot;any&quot;,
                            &quot;value&quot;: []
                        }
                    ],
                    &quot;op&quot;: &quot;OR&quot;
                },
                &quot;expired_at&quot;: 4102444800
            }
        ]
    }
}</code></pre><h1 id="policy-subjects-id">policy subjects 根据策略 ID 拉群策略对应的用户信息</h1>
<p>基于 LBAC 方案, 最终每个资源会打上一批 label, 这批 label 对应一批 Policy IDs
查询这个资源的有某个权限的用户列表时, 可以将这批 Policy IDs 作为这个接口参数, 查询<code>用户列表</code></p>
<p>注意: 
- 只能查询自己系统的策略列表对应的<code>用户列表</code>
- 如果 policyID 是其他系统的, 将会被<code>过滤掉</code>, 接口正常, 但对应的 policyId 不会出现在结果列表中</p>
<h4 id="url">URL</h4>
<blockquote>
<p>GET /api/v1/systems/{system_id}/policies/-/subjects</p>
</blockquote>
<h4 id="parameters">Parameters</h4>
<table>
<thead>
<tr>
<th align="left">字段</th>
<th align="left">类型</th>
<th align="left">是否必须</th>
<th align="left">位置</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">system_id</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">path</td>
<td align="left">系统 ID</td>
</tr>
<tr>
<td align="left">ids</td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left">query</td>
<td align="left">策略 id, 多个以英文逗号分隔</td>
</tr>
</tbody>
</table>
<p>示例: <code>ids=2,3,4,7,9</code></p>
<h4 id="response">Response</h4>
<pre class="codehilite"><code class="language-json">{
    &quot;code&quot;: 0,
    &quot;message&quot;: &quot;ok&quot;,
    &quot;data&quot;: [
        {
            &quot;id&quot;: 2,
            &quot;subject&quot;: {
                &quot;type&quot;: &quot;user&quot;,
                &quot;id&quot;: &quot;admin&quot;,
                &quot;name&quot;: &quot;管理员&quot;
            }
        },
        {
            &quot;id&quot;: 3,
            &quot;subject&quot;: {
                &quot;type&quot;: &quot;user&quot;,
                &quot;id&quot;: &quot;test2&quot;,
                &quot;name&quot;: &quot;test2&quot;
            }
        },
        {
            &quot;id&quot;: 4,
            &quot;subject&quot;: {
                &quot;type&quot;: &quot;user&quot;,
                &quot;id&quot;: &quot;test1&quot;,
                &quot;name&quot;: &quot;test1&quot;
            }
        },
        {
            &quot;id&quot;: 7,
            &quot;subject&quot;: {
                &quot;type&quot;: &quot;user&quot;,
                &quot;id&quot;: &quot;admin&quot;,
                &quot;name&quot;: &quot;管理员&quot;
            }
        }
    ]
}</code></pre><h1 id="api">接入系统管理类 API 背景作用等说明</h1>
<p>TODO 待补充</p><h1 id="api">接入系统管理类 API</h1>
<ul>
<li><a href="./00-Concepts.md">名词及概念</a></li>
<li><a href="./01-CreateGradeManager.md">创建分级管理员</a></li>
<li><a href="./02-ListGradeManagerMember.md">查询分级管理员成员列表</a></li>
<li><a href="./03-AddGradeManagerMember.md">添加分级管理员成员</a></li>
<li><a href="./04-DeleteGradeManagerMember.md">删除分级管理员成员</a></li>
<li><a href="./05-ListGroup.md">查询用户组列表</a></li>
<li><a href="./06-CreateGroup.md">创建用户组</a></li>
<li><a href="./07-UpdateGroupInfo.md">更新用户组名称和描述</a></li>
<li><a href="./08-DeleteGroup.md">删除用户组</a></li>
<li><a href="./09-ListGroupMember.md">查询用户组成员列表</a></li>
<li><a href="./10-AddGroupMember.md">添加用户组成员</a></li>
<li><a href="./11-DeleteGroupMember.md">删除用户组成员</a></li>
<li><a href="./12-GrantPolicyToGroup.md">用户组授权</a></li>
<li><a href="./13-ListUserJoinGradeManager.md">查询用户的分级管理员列表</a></li>
<li><a href="./14-ListUserJoinGroupInGradeManager.md">查询用户在某个分级管理员下的加入的用户组列表</a></li>
<li><a href="./15-CreateGroupApplication.md">创建用户组申请单据</a></li>
</ul><h1 id="api">超级管理类 API 背景作用等说明</h1>
<p>TODO 待补充</p><h1 id="api">超级管理类 API</h1>
<ul>
<li><a href="./00-Concepts.md">名词及概念</a></li>
<li><a href="./01-ListGlobalGroup.md">查询用户组列表</a></li>
<li><a href="./02-ListGroupMember.md">查询用户组成员列表</a></li>
<li><a href="./03-ListGroupOfSubjectJoined.md">查询 Subject 加入的用户组列表</a></li>
</ul><h1 id="python-sdk">Python SDK</h1>
<p>python 版 SDK 已经基本完成, 可以参考其代码/使用文档/单元测试用例</p>
<ul>
<li><a href="https://github.com/TencentBlueKing/iam-python-sdk">Github: TencentBlueKing/iam-python-sdk</a></li>
<li>详细使用文档 <a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/docs/usage.md">usage.md</a></li>
<li>SDK 整体入口 <code>iam/iam.py</code></li>
<li>测试用例 <code>tests/</code></li>
</ul>
<h3 id="features">Features</h3>
<ul>
<li>[Basic] 兼容 Python2/Python3</li>
<li>[Basic] 完备的单元测试</li>
<li>[Basic] 支持 debug 调试完整流程</li>
<li>[IAM] 支持条件表达式求值: 策略查询/鉴权/获取有权限的用户列表</li>
<li>[IAM] 支持条件表达式解析: 转换成 Django QuerySet 及 SQL 语句</li>
<li>[IAM] 获取无权限申请跳转 URL</li>
<li>[IAM] 支持批量资源鉴权 / 支持批量资源批量 action 是否有权限判断</li>
<li>[Contrib] Django IAM Migration, 整合 iam 模型 migration 到 Django Migration</li>
<li>[Contrib] Resource API Framework, 协助构建需要提供给 IAM 调用的 Resource API</li>
<li>[Contrib] 支持 tastypie</li>
</ul><h1 id="go-sdk">Go SDK</h1>
<p>Go 版 SDK 目前仅完成基本的鉴权逻辑</p>
<ul>
<li><a href="https://github.com/TencentBlueKing/iam-go-sdk">Github: TencentBlueKing/iam-go-sdk</a></li>
<li>详细使用文档 <a href="https://github.com/TencentBlueKing/iam-go-sdk/blob/master/docs/usage.md">usage.md</a></li>
</ul>
<h3 id="features">Features</h3>
<ul>
<li>鉴权支持: IsAllowed / IsAllowedWithCache</li>
<li>单个操作批量资源鉴权: BatchIsAllowed</li>
<li>单个资源批量操作鉴权: ResourceMultiActionsAllowed</li>
<li>批量资源批量操作鉴权: BatchResourceMultiActionsAllowed</li>
<li>生成无权限申请 URL: GetApplyURL</li>
<li>生成无权限协议 json: GenPermissionApplyData</li>
<li>资源反向拉取接口 basic auth 鉴权: IsBasicAuthAllowed  / 以及 basic auth middleware</li>
<li>获取系统 Token: GetToken</li>
<li>支持 prometheus 统计接口调用信息</li>
<li>支持反向拉取框架 dispatcher/provider interface</li>
</ul><h1 id="java-sdk">Java SDK</h1>
<p>待开源</p><h1 id="php-sdk">PHP SDK</h1>
<p>php sdk 已经完成并开源</p>
<ul>
<li><a href="https://github.com/TencentBlueKing/iam-php-sdk">Github: TencentBlueKing/iam-php-sdk</a></li>
<li>详细使用文档 <a href="https://github.com/TencentBlueKing/iam-php-sdk/blob/master/docs/usage.md">usage.md</a></li>
<li>SDK 整体入口 <code>src/IAM.py</code></li>
<li>测试用例 <code>tests/</code></li>
</ul>
<h3 id="features">Features</h3>
<ul>
<li>鉴权支持: isAllowed / isAllowedWithCache</li>
<li>单个操作批量资源鉴权: batchIsAllowed</li>
<li>单个资源批量操作鉴权: resourceMultiActionsAllowed</li>
<li>批量资源批量操作鉴权: batchResourceMultiActionsAllowed</li>
<li>生成无权限申请 URL: getApplyURL</li>
<li>资源反向拉取接口 basic auth 鉴权: isBasicAuthAllowed</li>
<li>获取系统 Token: getToken</li>
</ul><h1 id="sdk">SDK 测试用例</h1>
<h2 id="_1">背景</h2>
<p>新版权限中心只进行<code>策略管理</code>, 资源本身还在各个接入系统;</p>
<p>此时从权限中心获取策略之后, 需要拿本地资源进行计算求值(eval)</p>
<p>例如权限中心返回表达式</p>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;OR&quot;,
        &quot;content&quot;: [
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;host.id&quot;,
                &quot;value&quot;: &quot;a1&quot;
            },
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;host.name&quot;,
                &quot;value&quot;: &quot;b1&quot;
            },
        ]
}</code></pre>


<p>会拿本地的资源带入表达式计算结果, 此时资源的<code>id</code>及<code>attr</code>可以表示为一个<code>json</code></p>
<pre class="codehilite"><code class="language-json">{
    &quot;id&quot;: &quot;a1&quot;,
    &quot;name&quot;: &quot;xxxx&quot;
}</code></pre>


<p>计算逻辑:
- <code>attr</code> op <code>value</code>
- <code>("a1" eq "a1") OR ("xxxx" eq "b1")</code>
- 最终结果: <code>True</code></p>
<p>为了确保各个语言实现的 sdk 逻辑一致性, 这里提供了几个关键细节的测试用例, 需要各个 SDK 实现对应单元测试, 确保逻辑正确性</p>
<h2 id="_2">关键</h2>
<ul>
<li>根据 <a href="../../Reference/Expression/01-Schema.md">条件表达式协议</a>, 计算表达式中存在两种操作符, postive (<code>eq/in/contains/starts_with/ends_with</code>)和 negative(<code>not_eq/not_in/not_contains/not_starts_with/not_ends_with</code>)</li>
<li>条件表达式中的<code>value</code>可能是单一值, 也可能是个列表</li>
<li>用户资源的属性<code>attr</code>可能是单一值, 也可能是个列表</li>
<li>计算逻辑, 会比较 <code>value</code> 和 <code>attr</code>中的每一个值 (相当于逐一比较)</li>
<li>
<p>具体: </p>
<ul>
<li>postive 则 <code>value</code>和<code>attr</code>中, 一个求值<code>True</code>则<code>pass</code>, 全部求值<code>False</code>则<code>no pass</code></li>
<li>举例: <code>op=eq, value=[1, 2]</code> 及 <code>resource.attr=[2, 3]</code>, 求值结果<code>pass</code></li>
<li>negative 则 <code>value</code>和<code>attr</code>中, 全部求值 True 则 pass, 一个求值 False 则<code>no pass</code></li>
<li>举例: <code>op=not_eq, value=[1, 2]</code>及<code>resource.attr=[2, 3]</code>, 求值结果<code>no pass</code></li>
</ul>
</li>
<li>
<p>ANY 操作符, 不需要计算, <code>op=any</code>则<code>pass</code></p>
</li>
<li>
<p>特殊集合操作: IN 操作符, <code>op=in</code> / <code>op=not_in</code> </p>
<ul>
<li><code>attr</code> in <code>value</code>: 如果<code>attr=[1,2]</code>, 需要逐一判定<code>1</code>/<code>2</code> 是否在 <code>value</code>中 =&gt; <code>1</code>/<code>2</code>只要一个在<code>value</code>中则<code>True</code>; 否则<code>False</code></li>
<li><code>attr</code> not_in <code>value</code>: 如果<code>attr=[1,2]</code>, 需要逐一判定<code>1</code>/<code>2</code> 不在 <code>value</code>中 =&gt; <code>1</code>/<code>2</code>两个都不在<code>value</code>中则<code>True</code>; 否则<code>False</code></li>
</ul>
</li>
<li>特殊集合操作: Contains 操作符, <code>op=contains</code> / <code>op=not_contains</code><ul>
<li><code>attr</code> contains <code>value</code>: 如果<code>value=[3, 4]</code>, 需要逐一判定<code>attr</code>包含<code>3</code>/<code>4</code> =&gt; <code>attr</code>包含<code>3</code>/<code>4</code>中的一个则<code>True</code>; 全部不包含<code>False</code></li>
<li><code>attr</code> not_contains <code>value</code>: 如果<code>value=[3, 4]</code>, 需要逐一判定<code>attr</code>不包含<code>3</code>/<code>4</code> =&gt; <code>attr</code>全部不包含<code>3</code>/<code>4</code>则<code>True</code>; 否则<code>False</code></li>
</ul>
</li>
</ul>
<h2 id="_3">测试用例</h2>
<h3 id="1">1. 常规表达式</h3>
<h4 id="opand">OP=AND</h4>
<p>policy</p>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;OR&quot;,
        &quot;content&quot;: [
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;host.id&quot;,
                &quot;value&quot;: &quot;a1&quot;
            },
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;host.name&quot;,
                &quot;value&quot;: &quot;b1&quot;
            },
        ]
}</code></pre>


<p>resource</p>
<pre class="codehilite"><code class="language-json"># host
{
        &quot;id&quot;: &quot;a1&quot;,
        &quot;name&quot;: &quot;b1&quot;
}</code></pre>


<p>is_allowed: <code>True</code></p>
<h4 id="opor">OP=OR</h4>
<p>policy</p>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;OR&quot;,
        &quot;content&quot;: [
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;host.id&quot;,
                &quot;value&quot;: &quot;a1&quot;
            },
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;host.name&quot;,
                &quot;value&quot;: &quot;b1&quot;
            },
        ]
}</code></pre>


<p>resource</p>
<pre class="codehilite"><code class="language-json"># host
{
        &quot;id&quot;: &quot;a1&quot;,
        &quot;name&quot;: &quot;b1&quot;
}</code></pre>


<p>is_allowed: <code>True</code></p>
<h4 id="opeq">OP=EQ</h4>
<p>policy</p>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;eq&quot;,
        &quot;field&quot;: &quot;host.id&quot;,
        &quot;value&quot;: &quot;a1&quot;
}</code></pre>


<p>resource</p>
<pre class="codehilite"><code class="language-json">{
        &quot;id&quot;: &quot;a1&quot;,
        &quot;name&quot;: &quot;b1&quot;
}</code></pre>


<p>is_allowed: <code>True</code></p>
<h3 id="2-positiveeq">2. positive(eq 为例)</h3>
<p>policy</p>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;eq&quot;,
        &quot;field&quot;: &quot;host.id&quot;,
        &quot;value&quot;: VALUE
}</code></pre>


<p>resource</p>
<pre class="codehilite"><code class="language-json">{
        &quot;id&quot;: ATTR,
        &quot;name&quot;: &quot;b1&quot;
}</code></pre>


<table>
<thead>
<tr>
<th align="left">VALUE</th>
<th align="left">ATTR</th>
<th align="left">is_allowed</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">1</td>
<td align="left">1</td>
<td align="left">True</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">[1, 2]</td>
<td align="left">True</td>
</tr>
<tr>
<td align="left">3</td>
<td align="left">[1, 2]</td>
<td align="left">False</td>
</tr>
</tbody>
</table>
<ul>
<li><a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/iam/eval/operators.py#L114">python sdk 实现</a></li>
</ul>
<h3 id="3-negativenot_eq">3. negative(not_eq 为例)</h3>
<p>policy</p>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;not_eq&quot;,
        &quot;field&quot;: &quot;host.id&quot;,
        &quot;value&quot;: VALUE
}</code></pre>


<p>resource</p>
<pre class="codehilite"><code class="language-json">{
        &quot;id&quot;: ATTR,
        &quot;name&quot;: &quot;b1&quot;
}</code></pre>


<table>
<thead>
<tr>
<th align="left">VALUE</th>
<th align="left">ATTR</th>
<th align="left">is_allowed</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">1</td>
<td align="left">2</td>
<td align="left">True</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">1</td>
<td align="left">True</td>
</tr>
<tr>
<td align="left">3</td>
<td align="left">[1, 2]</td>
<td align="left">True</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">[1, 2]</td>
<td align="left">False</td>
</tr>
</tbody>
</table>
<ul>
<li><a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/iam/eval/operators.py#L182">python sdk 实现</a></li>
</ul>
<h3 id="4-in-and-not_in">4. in and not_in</h3>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;in&quot;,
        &quot;field&quot;: &quot;host.id&quot;,
        &quot;value&quot;: [&quot;a1&quot;, &quot;a3&quot;]    
}

# Resource 1, True
{
    &quot;id&quot;: [&quot;a4&quot;, &quot;a3&quot;],
}</code></pre>


<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;not_in&quot;,
        &quot;field&quot;: &quot;host.id&quot;,
        &quot;value&quot;: [&quot;a1&quot;, &quot;a3&quot;]    
}

# Resource 1, False
{
    &quot;id&quot;: [&quot;a4&quot;, &quot;a3&quot;],
}</code></pre>


<h3 id="5-contains-and-not_contains">5. contains and not_contains</h3>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;contains&quot;,
        &quot;field&quot;: &quot;host.id&quot;,
        &quot;value&quot;: [&quot;a1&quot;, &quot;a3&quot;]    
}

# Resource 1, True
{
    &quot;id&quot;: [&quot;a4&quot;, &quot;a3&quot;],
}</code></pre>


<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;not_contains&quot;,
        &quot;field&quot;: &quot;host.id&quot;,
        &quot;value&quot;: [&quot;a1&quot;, &quot;a3&quot;]    
}

# Resource 1, False
{
    &quot;id&quot;: [&quot;a4&quot;, &quot;a3&quot;],
}</code></pre>


<h3 id="6">6. 更多的测试用例</h3>
<p>可以参考 python-sdk 实现的各类操作符的用例</p>
<p>https://github.com/TencentBlueKing/iam-python-sdk/blob/master/tests/eval/test_operators.py</p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://github.com/TencentBlueKing/iam-python-sdk">iam-python-sdk 实现</a></li>
<li><a href="../../Reference/Expression/01-Schema.md">条件表达式协议</a></li>
</ul><h1 id="_1">表达式定义</h1>
<h2 id="_2">背景</h2>
<p>用户在权限中心申请的策略, 已表达式的形式存储; 而接入系统的资源信息只有各个系统自己知道;</p>
<p>在接入系统页面上, 展现一个用户有权限的某种资源列表时, 会到权限中心拉取对应策略, 返回得到表达式;</p>
<p>此时, 需要接入系统将表达式转换成自身存储的过滤逻辑, 筛选出对应的资源列表, 在页面上展现;</p>
<p>另一种场景: 在权限中心 SaaS 配置权限的页面上, 需要预览一个策略生效后对应的有权限的资源列表, 此时会拿条件表达式, 到接入系统提供的 API, 查询资源列表.</p>
<h2 id="_3">条件表达式处理策略</h2>
<ul>
<li>给到协议</li>
<li>各个接入方先自行解析, 转换成自己存储的查询</li>
<li>提取, 得到不同语言不同存储的查询转换, 例如<code>django queryset</code>/<code>raw sql</code>/<code>go mongodb</code></li>
</ul>
<h2 id="1">1. 定义</h2>
<p>定义</p>
<pre class="codehilite"><code class="language-graphql">input Filter{
    AND: [Filter!]
    OR: [Filter!]

    # String filters
    str eq: String
    str not_eq: String
    str in: [String!]
    str not_in: [String!]
    str contains: String
    str not_contains: String
    str starts_with: String
    str not_starts_with: String
    str ends_with: String
    str not_ends_with: String

    str any: String

    # Numeric filters
    num eq: Numeric
    num not_eq: Numeric
    num in: [Numeric!]
    num not_in: [Numeric!]
    num lt: Numeric
    num lte: Numeric
    num gt: Numeric
    num gte: Numeric

    # Boolean filters
    bool eq: Boolean
    bool not_eq: Boolean
}</code></pre>


<h2 id="2">2. 操作符</h2>
<table>
<thead>
<tr>
<th align="left">操作符</th>
<th align="left">操作对象类型</th>
<th align="left">支持类型</th>
<th align="left">V1 版支持(当前版本)</th>
<th align="left">V2 版支持</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">AND</td>
<td align="left">[Filter]</td>
<td align="left">Filter</td>
<td align="left">是</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">OR</td>
<td align="left">[Filter]</td>
<td align="left">Filter</td>
<td align="left">是</td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">eq</td>
<td align="left"></td>
<td align="left">string/numeric/boolean</td>
<td align="left">是</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">not_eq</td>
<td align="left"></td>
<td align="left">string/numeric/boolean</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">in</td>
<td align="left">[type]</td>
<td align="left">string/numeric/boolean</td>
<td align="left">是</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">not_in</td>
<td align="left">[type]</td>
<td align="left">string/numeric/boolean</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">contains</td>
<td align="left"></td>
<td align="left">string</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">not_contains</td>
<td align="left"></td>
<td align="left">string</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">starts_with</td>
<td align="left"></td>
<td align="left">string</td>
<td align="left">是</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">not_starts_with</td>
<td align="left"></td>
<td align="left">string</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">ends_with</td>
<td align="left"></td>
<td align="left">string</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">not_ends_with</td>
<td align="left"></td>
<td align="left">string</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">lt</td>
<td align="left"></td>
<td align="left">numeric</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">lte</td>
<td align="left"></td>
<td align="left">numeric</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">gt</td>
<td align="left"></td>
<td align="left">numeric</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">gte</td>
<td align="left"></td>
<td align="left">numeric</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">any</td>
<td align="left"></td>
<td align="left">string</td>
<td align="left">是, 目前只会用于 resource.id, 表示用户有所有这类资源的权限</td>
<td align="left"></td>
</tr>
</tbody>
</table>
<h2 id="3">3. 协议示例</h2>
<blockquote>
<p>and/or 是存在嵌套的</p>
</blockquote>
<pre class="codehilite"><code class="language-bash">id in [1, 2, 3]
|| os = linux
|| owner = admin
|| (path.startswith(/biz,1/) or path.startswith(/biz,2/))
|| (biz = bk and status = online)</code></pre>


<pre class="codehilite"><code class="language-json">{
    &quot;op&quot;: &quot;OR&quot;,
    &quot;content&quot;: [
    {
        &quot;op&quot;: &quot;in&quot;,
        &quot;field&quot;: &quot;host.id&quot;,
        &quot;value&quot;: [1, 2, 3]
    },
    {
        &quot;op&quot;: &quot;eq&quot;,
        &quot;field&quot;: &quot;host.os&quot;,
        &quot;value&quot;: &quot;linux&quot;
    },
    {
        &quot;op&quot;: &quot;eq&quot;,
        &quot;field&quot;: &quot;host.owner&quot;,
        &quot;value&quot;: &quot;admin&quot;
    },
    {
        &quot;op&quot;: &quot;OR&quot;,
        &quot;content&quot;: [
        {
            &quot;op&quot;: &quot;starts_with&quot;,
            &quot;field&quot;: &quot;host._bk_iam_path_&quot;,
            &quot;value&quot;: &quot;/biz,1/&quot;,
        },
        {
            &quot;op&quot;: &quot;starts_with&quot;,
            &quot;field&quot;: &quot;host._bk_iam_path_&quot;,
            &quot;value&quot;: &quot;/biz,2/&quot;,
        }]
    },
    {
        &quot;op&quot;: &quot;AND&quot;,
        &quot;content&quot;: [
        {
            &quot;op&quot;: &quot;eq&quot;,
            &quot;field&quot;: &quot;host.biz&quot;,
            &quot;value&quot;: &quot;bk&quot;
        },
        {
            &quot;op&quot;: &quot;eq&quot;,
            &quot;field&quot;: &quot;host.status&quot;,
            &quot;value&quot;: &quot;online&quot;
        }]
    }]
}</code></pre>


<h4 id="field">!! 注意 field 的格式</h4>
<pre class="codehilite"><code class="language-bash">- host.id 前缀host表示id属性需要查找的是host资源实例的id属性
- 如果操作有多个依赖资源, 比如job执行, 表达式中field可能会有host.id与job.id分别对于host资源的id属性与job资源的id属性</code></pre>


<h2 id="4">4. 转换成对应存储查询示例</h2>
<p>上面的条件表达式(给了一个相对复杂的配置, 实际获取得到的可能很简单, 取决于权限配置的复杂程度)</p>
<p>如果转换成<code>django queryset</code></p>
<pre class="codehilite"><code class="language-bash">Resource.objects.filter(
      Q(id__in=[1,2,3])
      | Q(os=&quot;linux&quot;)
      | Q(owner=&quot;admin&quot;)
      | (Q(path__startswith(&quot;/biz,1/&quot;)) |  Q(path__startswith(&quot;/biz,2/&quot;)))
      | (Q(biz=&quot;bk&quot;) &amp; Q(status=&quot;online&quot;))
)</code></pre>


<p>如果转换成 sql</p>
<pre class="codehilite"><code class="language-sql">SELECT *
FROM resource
WHERE id IN (1, 2, 3)
       OR os=&quot;linux&quot;
       OR owner=&quot;admin&quot;
       OR (path like &quot;/biz,1/%&quot; OR path like &quot;/biz,2/%&quot;)
       OR (biz=&quot;bk&quot; AND status=&quot;online&quot;)</code></pre>


<ul>
<li>其他存储, 例如 mongodb/elasticsearch 等等, 需要接入系统自行转换</li>
<li>权限中心返回的表达式中的 key/value 等, 是接入系统注册的模型 + 用户配置权限填充的内容;</li>
</ul>
<h2 id="5">5. 无关联资源的操作表达式说明</h2>
<pre class="codehilite"><code class="language-bash">{
    &quot;code&quot;: 0,
    &quot;data&quot;: {
        &quot;field&quot;: &quot;&quot;,
        &quot;op&quot;: &quot;any&quot;,
        &quot;value&quot;: []
    },
    &quot;message&quot;: &quot;ok&quot;
}</code></pre>


<p>没有关联资源类型的操作, 比如创建主机, 用户有权限的情况下返回的表达式如上, field 由于资源类型为空直接置空</p>
<h2 id="6">6. 参考资料</h2>
<ul>
<li>表达式协议参考了 graphql 的规范, 但是 graphql 没有具体的实现, 所以以下资料仅供参考, 需要自行实现</li>
<li>
<p>graphql spec 中没有涉及 filter 的, 目前是每种语言的实现自行定义了 filter 处理;</p>
<ul>
<li><a href="https://github.com/graphql/graphql-spec">graphql spec</a></li>
<li><a href="https://github.com/graphql/graphql-spec/issues/271">Proposal: Basic expression language for filters inside GraphQL</a></li>
<li><a href="https://github.com/graphql-python/graphene/issues/528">Graphene: How to make an OR/AND filtering</a></li>
</ul>
</li>
<li>
<p>多语言版本实现参考 <a href="https://www.howtographql.com/graphql-python/7-filtering/">howtographql</a></p>
</li>
</ul><h1 id="_1">表达式求值</h1>
<p>假设返回的条件表达式是:</p>
<pre class="codehilite"><code class="language-json">{
    &quot;op&quot;: &quot;OR&quot;,
    &quot;content&quot;: [
        {
            &quot;op&quot;: &quot;eq&quot;,
            &quot;field&quot;: &quot;job.id&quot;,
            &quot;value&quot;: [&quot;1&quot;, &quot;2&quot;]
        },
        {
            &quot;op&quot;: &quot;AND&quot;,
            &quot;content&quot;: [
                {
                    &quot;op&quot;: &quot;eq&quot;,
                    &quot;field&quot;: &quot;job.owner&quot;,
                    &quot;value&quot;: &quot;admin&quot;
                },
                {
                    &quot;op&quot;: &quot;eq&quot;,
                    &quot;field&quot;: &quot;job.os&quot;,
                    &quot;value&quot;: &quot;linux&quot;
                }
            ]
        }
    ]
}</code></pre>


<p>以上表达式等价的布尔运算:</p>
<pre class="codehilite"><code class="language-bash">id in [&quot;1&quot;, &quot;2&quot;] || ( owner == &quot;admin&quot; &amp;&amp; os == &quot;linux&quot; )</code></pre>


<p>表达式求值的过程, 就是将<code>资源</code>及其<code>属性</code>带入计算, 求表达式的<code>值</code></p>
<p><img alt="enter image description here" src="F:\v_awjliu\BKDocs\ZH/6.0/iam_dev_docs/assets/Reference/SDK/image_9.png" /></p>
<p>以上请求最终鉴权计算结果为 true</p>
<hr />
<p>具体表达式求值的实现可以参考 sdk 实现
- <a href="https://github.com/TencentBlueKing/iam-python-sdk/tree/master/iam/eval">Python SDK eval</a>
- <a href="https://github.com/TencentBlueKing/iam-python-sdk/tree/master/tests/eval">Python SDK eval unittest cases</a></p><h1 id="_1">表达式解析</h1>
<p>如果想获取<code>某个用户有某个操作权限的资源列表</code></p>
<p>此时, 使用<code>用户+操作</code>到权限中心查询, 获取得到策略条件表达式;</p>
<p>需要解析条件表达式为<code>自身存储</code>的查询条件, 查询得到资源列表.</p>
<h2 id="sql">转换成 SQL 语句</h2>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;AND&quot;,
        &quot;content&quot;: [
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;id&quot;,
                &quot;value&quot;: &quot;1&quot;,
            },
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;name&quot;,
                &quot;value&quot;: &quot;test&quot;,
            }
        ]
    }</code></pre>


<p>得到: <code>(id == '1' AND name == 'test')</code></p>
<p>参考实现: <a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/iam/contrib/converter/sql.py">Python SDK SQLConverter</a></p>
<h2 id="django-queryset">转换成 Django QuerySet</h2>
<pre class="codehilite"><code class="language-json">{
        &quot;op&quot;: &quot;AND&quot;,
        &quot;content&quot;: [
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;id&quot;,
                &quot;value&quot;: &quot;1&quot;
            }, 
            {
                &quot;op&quot;: &quot;eq&quot;,
                &quot;field&quot;: &quot;name&quot;,
                &quot;value&quot;: &quot;test&quot;
            }
        ],
    }</code></pre>


<p>得到: <code>Q(id="1") &amp; Q(name="test")</code></p>
<p>参考实现: <a href="https://github.com/TencentBlueKing/iam-python-sdk/blob/master/iam/contrib/converter/queryset.py">Python SDK DjangoQuerySetConverter</a></p><h1 id="_1">性能测试说明</h1>
<h2 id="_2">测试环境</h2>
<ul>
<li>CPU: 8 Core Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GHz</li>
<li>Memory: 8G </li>
</ul>
<h2 id="_3">测试数据</h2>
<p>目前仅使用个人常规的策略进行<code>基准</code>测试, 不涉及复杂的继承.</p>
<h4 id="1-api-apiv1policyquery">1.策略查询 API <code>/api/v1/policy/query</code></h4>
<ul>
<li><a href="../Reference/API/04-Auth/01-SDK.md">API 文档</a></li>
<li>压测命令: <code>wrk -t8 -c100 -d60s --latency -s post.query.lua http://{IP}:{PORT}/api/v1/policy/query</code></li>
<li>测试数据</li>
</ul>
<pre class="codehilite"><code class="language-bash">Running 1m test @ http://{IP}:{PORT}//api/v1/policy/query
  8 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     8.19ms    0.99ms  36.51ms   94.78%
    Req/Sec     1.47k    85.45     4.32k    95.45%
  Latency Distribution
     50%    7.96ms
     75%    8.24ms
     90%    8.96ms
     99%   10.48ms
  704377 requests in 1.00m, 186.75MB read
Requests/sec:  11721.59
Transfer/sec:      3.11MB</code></pre>


<ul>
<li>说明<ul>
<li>简单策略查询耗时: <code>&lt;10ms</code></li>
<li>复杂策略查询耗时: <code>&lt;100ms</code></li>
</ul>
</li>
<li>依赖: 从数据库查询一次后, 放入 redis, 所以如果发现耗时比较多, 可以查看权限中心日志, 确认 sql 执行耗时/redis 执行耗时/请求耗时等, 确认是否是由于 mysql/redis 原因导致请求比较慢;</li>
</ul>
<p>如果发现鉴权耗时很慢, 那么可能有两个原因:
1. 请求鉴权接口慢.  DNS 解析/网络耗时, 可以通过权限中心的请求日志确认耗时
2. 本地计算慢. 可能是该用户涉及权限策略过多, 查询返回后, 本地计算比较慢. 例如
    - 给一个用户授权了 10000 个实例权限, 策略数据比较大, 计算比较慢.  此时应该给这个用户授权<code>范围</code>权限, 而不是 10000 个实例权限.
    - 把一个用户加入 100 个组/用户属于 100 个部门等, 会自动继承部门/组的权限, 导致策略数据比较大. 此时应该减少这个用户加入的组/部门.</p>
<h4 id="2-api-apiv1policyauth">2.鉴权计算 API <code>/api/v1/policy/auth</code></h4>
<ul>
<li><a href="../Reference/API/04-Auth/02-DirectAPI.md">API 文档</a></li>
<li>压测命令: <code>wrk -t8 -c100 -d60s --latency -s post.query.lua http://{IP}:{PORT}/api/v1/policy/auth</code></li>
<li>测试数据</li>
</ul>
<pre class="codehilite"><code class="language-bash">Running 1m test @ http://{IP}:{PORT}//api/v1/policy/auth
  8 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     8.04ms    0.98ms  46.68ms   94.05%
    Req/Sec     1.50k   101.82     5.30k    96.82%
  Latency Distribution
     50%    7.82ms
     75%    8.05ms
     90%    8.84ms
     99%   10.66ms
  717322 requests in 1.00m, 150.50MB read
Requests/sec:  11935.97
Transfer/sec:      2.50MB</code></pre>


<p>注意: 
- 这个 API 是给非 SDK 接入/无跨系统资源依赖的<code>小型系统/脚本/后台任务</code>使用的. 
- 中大型系统/平台类系统不要使用这个接口.
- 该接口耗费服务端资源较大, 后续会进行流控/熔断/服务降级</p>
    </body>
    </html>
    